Browse Source

Lowlevel USB enumerator for libusb

Luke Dashjr 12 years ago
parent
commit
dd43825dbb
8 changed files with 229 additions and 85 deletions
  1. 4 0
      Makefile.am
  2. 1 0
      configure.ac
  3. 3 2
      driver-x6500.c
  4. 2 1
      fpgautils.c
  5. 18 69
      ft232r.c
  6. 135 0
      lowl-usb.c
  7. 58 13
      lowlevel.c
  8. 8 0
      lowlevel.h

+ 4 - 0
Makefile.am

@@ -180,6 +180,10 @@ bfgminer_SOURCES += iospeeds.h iospeeds_posix.h
 endif
 endif
 
+if HAVE_LIBUSB
+bfgminer_SOURCES += lowl-usb.c
+endif
+
 if NEED_BFG_LOWLEVEL
 bfgminer_SOURCES += lowlevel.c lowlevel.h
 endif

+ 1 - 0
configure.ac

@@ -915,6 +915,7 @@ AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([HAVE_SENSORS], [test x$with_sensors = xyes])
 AM_CONDITIONAL([HAVE_CYGWIN], [test x$have_cygwin = xtrue])
+AM_CONDITIONAL([HAVE_LIBUSB], [test x$libusb = xyes])
 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])

+ 3 - 2
driver-x6500.c

@@ -133,8 +133,9 @@ static bool x6500_foundlowl(struct lowlevel_device_info * const info, __maybe_un
 	const char * const serial = info->serial;
 	if (info->lowl != &lowl_ft232r)
 	{
-		applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
-		       __func__, product, serial);
+		if (info->lowl != &lowl_usb)
+			applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
+			       __func__, product, serial);
 		return false;
 	}
 	

+ 2 - 1
fpgautils.c

@@ -657,7 +657,8 @@ bool _serial_autodetect_found_cb(struct lowlevel_device_info * const devinfo, vo
 	}
 	if (devinfo->lowl != &lowl_vcom)
 	{
-		applog(LOG_WARNING, "Non-VCOM %s (%s) matched", devinfo->path, devinfo->devid);
+		if (devinfo->lowl != &lowl_usb)
+			applog(LOG_WARNING, "Non-VCOM %s (%s) matched", devinfo->path, devinfo->devid);
 		return false;
 	}
 	detectone_meta_info = (struct detectone_meta_info_t){

+ 18 - 69
ft232r.c

@@ -30,25 +30,6 @@
 #define FT232R_IDVENDOR   0x0403
 #define FT232R_IDPRODUCT  0x6001
 
-static
-char *ft232r_libusb_dup_string(libusb_device_handle * const handle, const uint8_t idx, const char * const idxname)
-{
-	if (!idx)
-		return NULL;
-	unsigned char buf[0x100];
-	const int n = libusb_get_string_descriptor_ascii(handle, idx, buf, sizeof(buf)-1);
-	if (unlikely(n < 0)) {
-		applog(LOG_ERR, "ft232r_scan: Error getting USB string %d (%s): %s",
-		       idx, idxname, bfg_strerror(n, BST_LIBUSB));
-		return NULL;
-	}
-	if (n == 0)
-		return NULL;
-	buf[n] = '\0';
-	return strdup((void*)buf);
-}
-
-
 static
 void ft232r_devinfo_free(struct lowlevel_device_info * const info)
 {
@@ -57,61 +38,29 @@ void ft232r_devinfo_free(struct lowlevel_device_info * const info)
 		libusb_unref_device(dev);
 }
 
+static
+bool _ft232r_devinfo_scan_cb(struct lowlevel_device_info * const usbinfo, void * const userp)
+{
+	struct lowlevel_device_info **devinfo_list_p = userp, *info;
+	
+	info = malloc(sizeof(*info));
+	*info = (struct lowlevel_device_info){
+		.lowl = &lowl_ft232r,
+		.lowl_data = libusb_ref_device(usbinfo->lowl_data),
+	};
+	lowlevel_devinfo_semicpy(info, usbinfo);
+	LL_PREPEND(*devinfo_list_p, info);
+	
+	// Never *consume* the lowl_usb entry - especially since this is during the scan!
+	return false;
+}
+
 static
 struct lowlevel_device_info *ft232r_devinfo_scan()
 {
 	struct lowlevel_device_info *devinfo_list = NULL;
-	ssize_t count, i;
-	libusb_device **list;
-	struct libusb_device_descriptor desc;
-	libusb_device_handle *handle;
-	struct lowlevel_device_info *info;
-	int err;
-
-	if (unlikely(!have_libusb))
-		return NULL;
 	
-	count = libusb_get_device_list(NULL, &list);
-	if (unlikely(count < 0)) {
-		applog(LOG_ERR, "ft232r_scan: Error getting USB device list: %s", bfg_strerror(count, BST_LIBUSB));
-		return NULL;
-	}
-
-	for (i = 0; i < count; ++i) {
-		err = libusb_get_device_descriptor(list[i], &desc);
-		if (unlikely(err)) {
-			applog(LOG_ERR, "ft232r_scan: Error getting device descriptor: %s", bfg_strerror(err, BST_LIBUSB));
-			continue;
-		}
-		if (!(desc.idVendor == FT232R_IDVENDOR && desc.idProduct == FT232R_IDPRODUCT)) {
-			applog(LOG_DEBUG, "ft232r_scan: Found %04x:%04x - not a ft232r", desc.idVendor, desc.idProduct);
-			continue;
-		}
-
-		info = malloc(sizeof(struct lowlevel_device_info));
-		*info = (struct lowlevel_device_info){
-			.lowl = &lowl_ft232r,
-			.devid = bfg_make_devid_libusb(list[i]),
-			.lowl_data = libusb_ref_device(list[i]),
-		};
-		
-		err = libusb_open(list[i], &handle);
-		if (unlikely(err))
-			applog(LOG_ERR, "ft232r_scan: Error opening device: %s", bfg_strerror(err, BST_LIBUSB));
-		else
-		{
-			info->manufacturer = ft232r_libusb_dup_string(handle, desc.iManufacturer, "iManufacturer");
-			info->product = ft232r_libusb_dup_string(handle, desc.iProduct, "iProduct");
-			info->serial = ft232r_libusb_dup_string(handle, desc.iSerialNumber, "iSerialNumber");
-			libusb_close(handle);
-		}
-
-		LL_PREPEND(devinfo_list, info);
-
-		applog(LOG_DEBUG, "ft232r_scan: Found \"%s\" serial \"%s\"", info->product, info->serial);
-	}
-
-	libusb_free_device_list(list, 1);
+	lowlevel_detect_id(_ft232r_devinfo_scan_cb, &devinfo_list, &lowl_usb, FT232R_IDVENDOR, FT232R_IDPRODUCT);
 	
 	return devinfo_list;
 }

+ 135 - 0
lowl-usb.c

@@ -0,0 +1,135 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libusb.h>
+
+#include "fpgautils.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "miner.h"
+#include "util.h"
+
+static
+char *lowl_libusb_dup_string(libusb_device_handle * const handle, const uint8_t idx, const char * const idxname, const char * const fname)
+{
+	if (!idx)
+		return NULL;
+	unsigned char buf[0x100];
+	const int n = libusb_get_string_descriptor_ascii(handle, idx, buf, sizeof(buf)-1);
+	if (unlikely(n < 0)) {
+		applog(LOG_ERR, "%s: Error getting USB string %d (%s): %s",
+		       fname, idx, idxname, bfg_strerror(n, BST_LIBUSB));
+		return NULL;
+	}
+	if (n == 0)
+		return NULL;
+	buf[n] = '\0';
+	return strdup((void*)buf);
+}
+
+
+static
+void usb_devinfo_free(struct lowlevel_device_info * const info)
+{
+	libusb_device * const dev = info->lowl_data;
+	if (dev)
+		libusb_unref_device(dev);
+}
+
+static
+struct lowlevel_device_info *usb_devinfo_scan()
+{
+	struct lowlevel_device_info *devinfo_list = NULL;
+	ssize_t count, i;
+	libusb_device **list;
+	struct libusb_device_descriptor desc;
+	libusb_device_handle *handle;
+	struct lowlevel_device_info *info;
+	int err;
+
+	if (unlikely(!have_libusb))
+		return NULL;
+	
+	count = libusb_get_device_list(NULL, &list);
+	if (unlikely(count < 0)) {
+		applog(LOG_ERR, "%s: Error getting USB device list: %s",
+		       __func__, bfg_strerror(count, BST_LIBUSB));
+		return NULL;
+	}
+
+	for (i = 0; i < count; ++i) {
+		err = libusb_get_device_descriptor(list[i], &desc);
+		if (unlikely(err)) {
+			applog(LOG_ERR, "%s: Error getting device descriptor: %s",
+			       __func__, bfg_strerror(err, BST_LIBUSB));
+			continue;
+		}
+
+		info = malloc(sizeof(struct lowlevel_device_info));
+		*info = (struct lowlevel_device_info){
+			.lowl = &lowl_usb,
+			.devid = bfg_make_devid_libusb(list[i]),
+			.lowl_data = libusb_ref_device(list[i]),
+			.vid = desc.idVendor,
+			.pid = desc.idProduct,
+		};
+		
+		err = libusb_open(list[i], &handle);
+		if (unlikely(err))
+			applog(LOG_ERR, "%s: Error opening device: %s",
+			       __func__, bfg_strerror(err, BST_LIBUSB));
+		else
+		{
+			info->manufacturer = lowl_libusb_dup_string(handle, desc.iManufacturer, "iManufacturer", __func__);
+			info->product = lowl_libusb_dup_string(handle, desc.iProduct, "iProduct", __func__);
+			info->serial = lowl_libusb_dup_string(handle, desc.iSerialNumber, "iSerialNumber", __func__);
+			libusb_close(handle);
+		}
+
+		LL_PREPEND(devinfo_list, info);
+	}
+
+	libusb_free_device_list(list, 1);
+	
+	return devinfo_list;
+}
+
+struct libusb_device_handle *lowl_usb_open(struct lowlevel_device_info * const info)
+{
+	libusb_device * const dev = info->lowl_data;
+	
+	if (!dev)
+		return NULL;
+	
+	libusb_device_handle *devh;
+
+	if (libusb_open(dev, &devh)) {
+		applog(LOG_ERR, "%s: Error opening device", __func__);
+		return NULL;
+	}
+	return devh;
+}
+
+void lowl_usb_close(struct libusb_device_handle * const devh)
+{
+	libusb_close(devh);
+}
+
+struct lowlevel_driver lowl_usb = {
+	.dname = "usb",
+	.devinfo_scan = usb_devinfo_scan,
+	.devinfo_free = usb_devinfo_free,
+};

+ 58 - 13
lowlevel.c

@@ -9,6 +9,7 @@
 
 #include "config.h"
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -19,6 +20,18 @@
 
 static struct lowlevel_device_info *devinfo_list;
 
+void lowlevel_devinfo_semicpy(struct lowlevel_device_info * const dst, const struct lowlevel_device_info * const src)
+{
+#define COPYSTR(key)  BFGINIT(dst->key, maybe_strdup(src->key))
+	COPYSTR(manufacturer);
+	COPYSTR(product);
+	COPYSTR(serial);
+	COPYSTR(path);
+	COPYSTR(devid);
+	BFGINIT(dst->vid, src->vid);
+	BFGINIT(dst->pid, src->pid);
+}
+
 void lowlevel_devinfo_free(struct lowlevel_device_info * const info)
 {
 	if (info->lowl->devinfo_free)
@@ -51,6 +64,11 @@ void lowlevel_scan()
 	
 	lowlevel_scan_free();
 	
+#ifdef HAVE_LIBUSB
+	devinfo_mid_list = lowl_usb.devinfo_scan();
+	LL_CONCAT(devinfo_list, devinfo_mid_list);
+#endif
+	
 #ifdef USE_X6500
 	devinfo_mid_list = lowl_ft232r.devinfo_scan();
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
@@ -68,22 +86,41 @@ void lowlevel_scan()
 	
 	LL_FOREACH(devinfo_list, devinfo_mid_list)
 	{
-		applog(LOG_DEBUG, "%s: Found %s device at %s (path=%s, manuf=%s, prod=%s, serial=%s)",
+		applog(LOG_DEBUG, "%s: Found %s device at %s (path=%s, vid=%04x, pid=%04x, manuf=%s, prod=%s, serial=%s)",
 		       __func__,
 		       devinfo_mid_list->lowl->dname,
 		       devinfo_mid_list->devid,
 		       devinfo_mid_list->path,
+		       (unsigned)devinfo_mid_list->vid, (unsigned)devinfo_mid_list->pid,
 		       devinfo_mid_list->manufacturer, devinfo_mid_list->product, devinfo_mid_list->serial);
 	}
 }
 
-int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles, void *userp)
+#define DETECT_BEGIN  \
+	struct lowlevel_device_info *info, *tmp;  \
+	int found = 0;  \
+	  \
+	LL_FOREACH_SAFE(devinfo_list, info, tmp)  \
+	{  \
+// END DETECT_BEGIN
+
+#define DETECT_PREEND  \
+		if (!cb(info, userp))  \
+			continue;  \
+		LL_DELETE(devinfo_list, info);  \
+		++found;  \
+// END DETECT_PREEND
+
+#define DETECT_END  \
+	}  \
+	return found;  \
+// END DETECT_END
+
+int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles, void * const userp)
 {
-	struct lowlevel_device_info *info, *tmp;
-	int found = 0, i;
+	int i;
 	
-	LL_FOREACH_SAFE(devinfo_list, info, tmp)
-	{
+	DETECT_BEGIN
 		if (serial && ((!info->serial) || strcmp(serial, info->serial)))
 			continue;
 		if (product_needles[0] && !info->product)
@@ -91,12 +128,20 @@ int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const cha
 		for (i = 0; product_needles[i]; ++i)
 			if (!strstr(info->product, product_needles[i]))
 				goto next;
-		if (!cb(info, userp))
-			continue;
-		LL_DELETE(devinfo_list, info);
-		++found;
+	DETECT_PREEND
 next: ;
-	}
-	
-	return found;
+	DETECT_END
+}
+
+int lowlevel_detect_id(const lowl_found_devinfo_func_t cb, void * const userp, const struct lowlevel_driver * const lowl, const int32_t vid, const int32_t pid)
+{
+	DETECT_BEGIN
+		if (info->lowl != lowl)
+			continue;
+		if (vid != -1 && vid != info->vid)
+			continue;
+		if (pid != -1 && pid != info->pid)
+			continue;
+	DETECT_PREEND
+	DETECT_END
 }

+ 8 - 0
lowlevel.h

@@ -2,6 +2,7 @@
 #define _BFG_LOWLEVEL_H
 
 #include <stdbool.h>
+#include <stdint.h>
 
 #include <uthash.h>
 
@@ -21,6 +22,8 @@ struct lowlevel_device_info {
 	char *serial;
 	char *path;
 	char *devid;
+	uint16_t vid;
+	uint16_t pid;
 	
 	struct lowlevel_driver *lowl;
 	void *lowl_data;
@@ -33,7 +36,9 @@ extern void lowlevel_scan();
 extern int _lowlevel_detect(lowl_found_devinfo_func_t, const char *serial, const char **product_needles, void *);
 #define lowlevel_detect(func, ...)  _lowlevel_detect(func, NULL, (const char *[]){__VA_ARGS__, NULL}, NULL)
 #define lowlevel_detect_serial(func, serial)  _lowlevel_detect(func, serial, (const char *[]){NULL}, NULL)
+extern int lowlevel_detect_id(lowl_found_devinfo_func_t, void *, const struct lowlevel_driver *, int32_t vid, int32_t pid);
 extern void lowlevel_scan_free();
+extern void lowlevel_devinfo_semicpy(struct lowlevel_device_info *dst, const struct lowlevel_device_info *src);
 extern void lowlevel_devinfo_free(struct lowlevel_device_info *);
 
 #ifdef USE_X6500
@@ -42,6 +47,9 @@ extern struct lowlevel_driver lowl_ft232r;
 #ifdef USE_NANOFURY
 extern struct lowlevel_driver lowl_mcp2210;
 #endif
+#ifdef HAVE_LIBUSB
+extern struct lowlevel_driver lowl_usb;
+#endif
 #ifdef HAVE_FPGAUTILS
 extern struct lowlevel_driver lowl_vcom;
 #endif