|
|
@@ -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);
|