Browse Source

mcp2210: Skeleton low-level driver for MCP2210 USB to SPI Master bridge

Luke Dashjr 12 years ago
parent
commit
869580b458
5 changed files with 204 additions and 0 deletions
  1. 4 0
      Makefile.am
  2. 23 0
      configure.ac
  3. 5 0
      lowlevel.c
  4. 3 0
      lowlevel.h
  5. 169 0
      mcp2210.c

+ 4 - 0
Makefile.am

@@ -243,6 +243,10 @@ endif
 if HAS_LITTLEFURY
 if HAS_LITTLEFURY
 bfgminer_SOURCES += driver-littlefury.c
 bfgminer_SOURCES += driver-littlefury.c
 endif
 endif
+
+if HAS_NANOFURY
+bfgminer_SOURCES += mcp2210.c
+endif
 endif
 endif
 
 
 bin_PROGRAMS += bfgminer-rpc
 bin_PROGRAMS += bfgminer-rpc

+ 23 - 0
configure.ac

@@ -581,6 +581,29 @@ fi
 AM_CONDITIONAL([HAS_LITTLEFURY], [test x$littlefury = xyes])
 AM_CONDITIONAL([HAS_LITTLEFURY], [test x$littlefury = xyes])
 
 
 
 
+driverlist="$driverlist nanofury"
+nanofury=auto
+AC_ARG_ENABLE([nanofury],
+	[AC_HELP_STRING([--disable-nanofury],[Compile support for NanoFury (default enabled)])],
+	[nanofury=$enableval]
+	)
+if test "x$nanofury" = "xno"; then
+	true
+elif test "x$bitfury" = "xyes"; then
+	nanofury=yes
+elif test "x$nanofury" = "xyes"; then
+	AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled NanoFury])
+else
+	nanofury=no
+fi
+if test "x$nanofury" = "xyes"; then
+	AC_DEFINE([USE_NANOFURY], [1], [Defined to 1 if NanoFury support is wanted])
+	need_fpgautils=yes
+	need_lowlevel=yes
+fi
+AM_CONDITIONAL([HAS_NANOFURY], [test x$nanofury = xyes])
+
+
 driverlist="$driverlist metabank"
 driverlist="$driverlist metabank"
 metabank=no
 metabank=no
 AC_ARG_ENABLE([metabank],
 AC_ARG_ENABLE([metabank],

+ 5 - 0
lowlevel.c

@@ -50,6 +50,11 @@ void lowlevel_scan()
 	devinfo_mid_list = lowl_ft232r.devinfo_scan();
 	devinfo_mid_list = lowl_ft232r.devinfo_scan();
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 #endif
 #endif
+	
+#ifdef USE_NANOFURY
+	devinfo_mid_list = lowl_mcp2210.devinfo_scan();
+	LL_CONCAT(devinfo_list, devinfo_mid_list);
+#endif
 }
 }
 
 
 int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles)
 int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles)

+ 3 - 0
lowlevel.h

@@ -32,5 +32,8 @@ extern void lowlevel_devinfo_free(struct lowlevel_device_info *);
 #ifdef USE_X6500
 #ifdef USE_X6500
 extern struct lowlevel_driver lowl_ft232r;
 extern struct lowlevel_driver lowl_ft232r;
 #endif
 #endif
+#ifdef USE_NANOFURY
+extern struct lowlevel_driver lowl_mcp2210;
+#endif
 
 
 #endif
 #endif

+ 169 - 0
mcp2210.c

@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012-2013 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.
+ */
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <hidapi/hidapi.h> /* FIXME */
+#include <utlist.h>
+
+#include "logging.h"
+#include "lowlevel.h"
+
+#define MCP2210_IDVENDOR   0x04d8
+#define MCP2210_IDPRODUCT  0x00de
+
+#ifdef WIN32
+#define HID_API_EXPORT __declspec(dllexport)
+#else
+#define HID_API_EXPORT /* */
+#endif
+struct hid_device_info HID_API_EXPORT *(*dlsym_hid_enumerate)(unsigned short, unsigned short);
+#define hid_enumerate dlsym_hid_enumerate
+void HID_API_EXPORT (*dlsym_hid_free_enumeration)(struct hid_device_info *);
+#define hid_free_enumeration dlsym_hid_free_enumeration
+
+#define LOAD_SYM(sym)  do { \
+	if (!(dlsym_ ## sym = dlsym(dlh, #sym))) {  \
+		applog(LOG_DEBUG, "%s: Failed to load %s in %s", __func__, #sym, dlname);  \
+		goto fail;  \
+	}  \
+} while(0)
+
+static
+bool hidapi_try_lib(const char * const dlname)
+{
+	struct hid_device_info *hid_enum;
+	void *dlh;
+	
+	dlh = dlopen(dlname, RTLD_NOW);
+	if (!dlh)
+	{
+		applog(LOG_DEBUG, "%s: Couldn't load %s: %s", __func__, dlname, dlerror());
+		return false;
+	}
+	
+	LOAD_SYM(hid_enumerate);
+	
+	hid_enum = hid_enumerate(0, 0);
+	if (!hid_enum)
+	{
+		applog(LOG_DEBUG, "%s: Loaded %s, but no devices enumerated; trying other libraries", __func__, dlname);
+		goto fail;
+	}
+	
+	LOAD_SYM(hid_free_enumeration);
+	hid_free_enumeration(hid_enum);
+	
+	applog(LOG_DEBUG, "%s: Successfully loaded %s", __func__, dlname);
+	
+	return true;
+
+fail:
+	dlclose(dlh);
+	return false;
+}
+
+static
+bool hidapi_load_library()
+{
+	if (dlsym_hid_free_enumeration)
+		return true;
+	
+	const char **p;
+	char dlname[23] = "libhidapi";
+	const char *dltry[] = {
+		"",
+		"-0",
+		"-hidraw",
+		"-libusb",
+		NULL
+	};
+	for (p = &dltry[0]; *p; ++p)
+	{
+		sprintf(&dlname[9], "%s.%s", *p,
+#ifdef WIN32
+		        "dll"
+#else
+		        "so"
+#endif
+		);
+		if (hidapi_try_lib(dlname))
+			return true;
+	}
+	
+	return false;
+}
+
+static
+void mcp2210_devinfo_free(struct lowlevel_device_info * const info)
+{
+	free(info->lowl_data);
+}
+
+static
+char *wcs2str_dup(wchar_t *ws)
+{
+	char tmp, *rv;
+	int clen;
+	
+	clen = snprintf(&tmp, 1, "%ls", ws);
+	++clen;
+	rv = malloc(clen);
+	snprintf(rv, clen, "%ls", ws);
+	return rv;
+}
+
+static
+struct lowlevel_device_info *mcp2210_devinfo_scan()
+{
+	if (!hidapi_load_library())
+	{
+		applog(LOG_DEBUG, "%s: Failed to load any hidapi library", __func__);
+		return NULL;
+	}
+	
+	struct hid_device_info *hid_enum, *hid_item;
+	struct lowlevel_device_info *info, *devinfo_list = NULL;
+	
+	hid_enum = hid_enumerate(MCP2210_IDVENDOR, MCP2210_IDPRODUCT);
+	if (!hid_enum)
+	{
+		applog(LOG_DEBUG, "%s: No MCP2210 devices found", __func__);
+		return NULL;
+	}
+	
+	LL_FOREACH(hid_enum, hid_item)
+	{
+		info = malloc(sizeof(struct lowlevel_device_info));
+		*info = (struct lowlevel_device_info){
+			.lowl = &lowl_mcp2210,
+			.lowl_data = strdup(hid_item->path),
+			.product = wcs2str_dup(hid_item->product_string),
+			.serial  = wcs2str_dup(hid_item->serial_number),
+		};
+		LL_PREPEND(devinfo_list, info);
+
+		applog(LOG_DEBUG, "%s: Found \"%s\" serial \"%s\"",
+		       __func__, info->product, info->serial);
+	}
+	
+	hid_free_enumeration(hid_enum);
+	
+	return devinfo_list;
+}
+
+struct lowlevel_driver lowl_mcp2210 = {
+	.devinfo_scan = mcp2210_devinfo_scan,
+	.devinfo_free = mcp2210_devinfo_free,
+};