Browse Source

ft232r: Complete necessary interfaces for X6500

Luke Dashjr 13 years ago
parent
commit
d684f9fbf4
2 changed files with 152 additions and 6 deletions
  1. 134 6
      ft232r.c
  2. 18 0
      ft232r.h

+ 134 - 6
ft232r.c

@@ -7,6 +7,10 @@
  * any later version.  See COPYING for more details.
  */
 
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
 #include <libusb-1.0/libusb.h>
 
 #include "fpgautils.h"
@@ -56,7 +60,7 @@ void ft232r_scan()
 
 	n = libusb_get_device_list(NULL, &list);
 	if (unlikely(n < 0)) {
-		applog(LOG_ERR, "ft232r scan: Error getting USB device list: %s", libusb_error_name(n));
+		applog(LOG_ERR, "ft232r_scan: Error getting USB device list: %s", libusb_error_name(n));
 		ft232r_devinfo_list = calloc(1, sizeof(struct ft232r_device_info *));
 		return;
 	}
@@ -66,7 +70,7 @@ void ft232r_scan()
 	for (i = 0; i < n; ++i) {
 		err = libusb_get_device_descriptor(list[i], &desc);
 		if (unlikely(err)) {
-			applog(LOG_ERR, "ft232r scan: Error getting device descriptor: %s", libusb_error_name(err));
+			applog(LOG_ERR, "ft232r_scan: Error getting device descriptor: %s", libusb_error_name(err));
 			continue;
 		}
 		if (!(desc.idVendor == FT232R_IDVENDOR && desc.idProduct == FT232R_IDPRODUCT))
@@ -74,14 +78,14 @@ void ft232r_scan()
 
 		err = libusb_open(list[i], &handle);
 		if (unlikely(err)) {
-			applog(LOG_ERR, "ft232r scan: Error opening device: %s", libusb_error_name(err));
+			applog(LOG_ERR, "ft232r_scan: Error opening device: %s", libusb_error_name(err));
 			continue;
 		}
 
 		n = libusb_get_string_descriptor_ascii(handle, desc.iProduct, buf, sizeof(buf)-1);
 		if (unlikely(n < 0)) {
 			libusb_close(handle);
-			applog(LOG_ERR, "ft232r scan: Error getting iProduct string: %s", libusb_error_name(n));
+			applog(LOG_ERR, "ft232r_scan: Error getting iProduct string: %s", libusb_error_name(n));
 			continue;
 		}
 		buf[n] = '\0';
@@ -91,7 +95,7 @@ void ft232r_scan()
 		n = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, buf, sizeof(buf)-1);
 		libusb_close(handle);
 		if (unlikely(n < 0)) {
-			applog(LOG_ERR, "ft232r scan: Error getting iSerialNumber string: %s", libusb_error_name(n));
+			applog(LOG_ERR, "ft232r_scan: Error getting iSerialNumber string: %s", libusb_error_name(n));
 			n = 0;
 		}
 		buf[n] = '\0';
@@ -99,7 +103,7 @@ void ft232r_scan()
 		info->libusb_dev = libusb_ref_device(list[i]);
 		ft232r_devinfo_list[found++] = info;
 
-		applog(LOG_DEBUG, "ft232r scan: Found \"%s\" serial \"%s\"", info->product, info->serial);
+		applog(LOG_DEBUG, "ft232r_scan: Found \"%s\" serial \"%s\"", info->product, info->serial);
 	}
 
 	ft232r_devinfo_list[found] = NULL;
@@ -127,6 +131,130 @@ int ft232r_detect(const char *product_needle, const char *serial, foundusb_func_
 	return found;
 }
 
+#define FTDI_REQTYPE  (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE)
+#define FTDI_REQTYPE_IN   (FTDI_REQTYPE | LIBUSB_ENDPOINT_IN)
+#define FTDI_REQTYPE_OUT  (FTDI_REQTYPE | LIBUSB_ENDPOINT_OUT)
+
+#define FTDI_REQUEST_RESET           0
+#define FTDI_REQUEST_SET_BAUDRATE    3
+#define FTDI_REQUEST_SET_BITMODE  0x0b
+
+#define FTDI_BAUDRATE_3M  0,0
+
+#define FTDI_INDEX       1
+#define FTDI_TIMEOUT  1000
+
+struct ft232r_device_handle {
+	libusb_device_handle *h;
+	uint8_t i;
+	uint8_t o;
+};
+
+struct ft232r_device_handle *ft232r_open(libusb_device *dev)
+{
+	// FIXME: Cleanup on errors
+	libusb_device_handle *devh;
+	struct ft232r_device_handle *ftdi;
+
+	if (libusb_open(dev, &devh)) {
+		applog(LOG_ERR, "ft232r_open: Error opening device");
+		return NULL;
+	}
+	libusb_detach_kernel_driver(devh, 0);
+	if (libusb_set_configuration(devh, 1)) {
+		applog(LOG_ERR, "ft232r_open: Error setting configuration");
+		return NULL;
+	}
+	if (libusb_claim_interface(devh, 0)) {
+		applog(LOG_ERR, "ft232r_open: Error claiming interface");
+		return NULL;
+	}
+	if (libusb_set_interface_alt_setting(devh, 0, 0)) {
+		applog(LOG_ERR, "ft232r_open: Error setting interface alt");
+		return NULL;
+	}
+	if (libusb_control_transfer(devh, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BAUDRATE, FTDI_BAUDRATE_3M, NULL, 0, FTDI_TIMEOUT) < 0) {
+		applog(LOG_ERR, "ft232r_open: Error performing control transfer");
+		return NULL;
+	}
+
+	ftdi = calloc(1, sizeof(*ftdi));
+	ftdi->h = devh;
+
+	struct libusb_config_descriptor *cfg;
+	if (libusb_get_config_descriptor(dev, 1, &cfg)) {
+		applog(LOG_ERR, "ft232r_open: Error getting config descriptor");
+		return NULL;
+	}
+	const struct libusb_interface_descriptor *altcfg = &cfg->interface[0].altsetting[0];
+	if (altcfg->bNumEndpoints < 2) {
+		applog(LOG_ERR, "ft232r_open: Too few endpoints");
+		return NULL;
+	}
+	ftdi->i = altcfg->endpoint[0].bEndpointAddress;
+	ftdi->o = altcfg->endpoint[1].bEndpointAddress;
+	libusb_free_config_descriptor(cfg);
+
+	return ftdi;
+}
+
+bool ft232r_purge_buffers(struct ft232r_device_handle *dev, enum ft232r_reset_purge purge)
+{
+	if (purge & FTDI_PURGE_RX)
+		if (libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_RESET, FTDI_PURGE_RX, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT))
+			return false;
+	if (purge & FTDI_PURGE_TX)
+		if (libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_RESET, FTDI_PURGE_TX, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT))
+			return false;
+	return true;
+}
+
+bool ft232r_set_bitmode(struct ft232r_device_handle *dev, uint8_t mask, uint8_t mode)
+{
+	return !libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BITMODE, (mode << 8) | mask, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT);
+}
+
+static ssize_t ft232r_readwrite(struct ft232r_device_handle *dev, unsigned char endpoint, void *data, size_t count)
+{
+	int transferred;
+	switch (libusb_bulk_transfer(dev->h, endpoint, data, count, &transferred, FTDI_TIMEOUT)) {
+		case LIBUSB_ERROR_TIMEOUT:
+			if (!transferred) {
+				errno = ETIMEDOUT;
+				return -1;
+			}
+		case 0:
+			return transferred;
+		default:
+			errno = EIO;
+			return -1;
+	}
+}
+
+ssize_t ft232r_write(struct ft232r_device_handle *dev, void *data, size_t count)
+{
+	return ft232r_readwrite(dev, dev->o, data, count);
+}
+
+ssize_t ft232r_write_all(struct ft232r_device_handle *dev, void *data, size_t count)
+{
+	char *p = data;
+	ssize_t writ, total = 0;
+
+	while (count && (writ = ft232r_write(dev, p, count)) > 0) {
+		p += writ;
+		count -= writ;
+		total += writ;
+	}
+	return total ?: writ;
+}
+
+// Caveat: Reads of less than 512 bytes may fail :(
+ssize_t ft232r_read(struct ft232r_device_handle *dev, void *buf, size_t count)
+{
+	return ft232r_readwrite(dev, dev->i, buf, count);
+}
+
 #if 0
 int main() {
 	libusb_init(NULL);

+ 18 - 0
ft232r.h

@@ -10,12 +10,30 @@
 #ifndef BFGMINER_FT232R_H
 #define BFGMINER_FT232R_H
 
+#include <stdbool.h>
+#include <stdint.h>
+
 #include <libusb-1.0/libusb.h>
 
+enum ft232r_reset_purge {
+	FTDI_PURGE_RX   = 1,
+	FTDI_PURGE_TX   = 2,
+	FTDI_PURGE_BOTH = 3,
+};
+
+struct ft232r_device_handle;
+
 typedef bool(*foundusb_func_t)(libusb_device *, const char *product, const char *serial);
 
 extern void ft232r_scan();
 extern void ft232r_scan_free();
 extern int ft232r_detect(const char *product_needle, const char *serial, foundusb_func_t);
+extern struct ft232r_device_handle *ft232r_open(libusb_device *);
+extern bool ft232r_purge_buffers(struct ft232r_device_handle *, enum ft232r_reset_purge);
+extern bool ft232r_set_bitmode(struct ft232r_device_handle *, uint8_t mask, uint8_t mode);
+extern ssize_t ft232r_write(struct ft232r_device_handle *, void *data, size_t count);
+extern ssize_t ft232r_write_all(struct ft232r_device_handle *, void *data, size_t count);
+// ft232r_read caveat: Reads of less than 512 bytes may fail :(
+extern ssize_t ft232r_read(struct ft232r_device_handle *, void *buf, size_t count);
 
 #endif