From 228f71d9b5e10c9b1957cd4344edc35aa0711d17 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 15 Oct 2022 22:28:06 +0200 Subject: [PATCH] src/libusb_ll: libusb wrapper (currently limited to scan device), src/main: add scan-usb option --- CMakeLists.txt | 2 + README.md | 1 + src/libusb_ll.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++++++ src/libusb_ll.hpp | 23 +++++++++ src/main.cpp | 15 ++++-- 5 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 src/libusb_ll.cpp create mode 100644 src/libusb_ll.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b309fe0..b3fa611 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,7 @@ set(OPENFPGALOADER_SOURCE src/ftdipp_mpsse.cpp src/main.cpp src/latticeBitParser.cpp + src/libusb_ll.cpp src/gowin.cpp src/device.cpp src/jlink.cpp @@ -145,6 +146,7 @@ set(OPENFPGALOADER_HEADERS src/jlink.hpp src/jtag.hpp src/jtagInterface.hpp + src/libusb_ll.hpp src/fsparser.hpp src/part.hpp src/board.hpp diff --git a/README.md b/README.md index c10a47c..2fd1f90 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ openFPGALoader -- a program to flash FPGA --protect-flash arg protect SPI flash area --quiet Produce quiet output (no progress bar) -r, --reset reset FPGA after operations + --scan-usb scan USB to display connected probes --skip-load-bridge skip writing bridge to SRAM when in write-flash mode --skip-reset skip resetting the device when in write-flash diff --git a/src/libusb_ll.cpp b/src/libusb_ll.cpp new file mode 100644 index 0000000..3db08cc --- /dev/null +++ b/src/libusb_ll.cpp @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (c) 2022 Gwenhael Goavec-Merou + */ + +#include +#include +#include +#include + +#include + +#include "cable.hpp" +#include "display.hpp" +#include "libusb_ll.hpp" + +using namespace std; + +libusb_ll::libusb_ll(int vid, int pid):_verbose(true) +{ + (void)vid; + (void)pid; + if (libusb_init(&_usb_ctx) < 0) + throw std::runtime_error("libusb_init_failed"); +} + +libusb_ll::~libusb_ll() +{ + libusb_exit(_usb_ctx); +} + +bool libusb_ll::scan() +{ + int i = 0; + libusb_device **dev_list; + libusb_device *usb_dev; + libusb_device_handle *handle; + + /* iteration */ + ssize_t list_size = libusb_get_device_list(_usb_ctx, &dev_list); + if (_verbose) + printInfo("found " + std::to_string(list_size) + " USB device"); + + char *mess = (char *)malloc(1024); + snprintf(mess, 1024, "%3s %3s %-13s %-15s %-12s %-20s %s", + "Bus", "device", "vid:pid", "probe type", "manufacturer", + "serial", "product"); + printSuccess(mess); + + while ((usb_dev = dev_list[i++]) != NULL) { + bool found = false; + struct libusb_device_descriptor desc; + if (libusb_get_device_descriptor(usb_dev, &desc) != 0) { + printError("Unable to get device descriptor"); + return false; + } + + char probe_type[256]; + + /* Linux host controller */ + if (desc.idVendor == 0x1d6b) + continue; + + /* ftdi devices */ + // FIXME: missing iProduct in cable_list + if (desc.idVendor == 0x403) { + if (desc.idProduct == 0x6010) + snprintf(probe_type, 256, "FTDI2232"); + else if (desc.idProduct == 0x6011) + snprintf(probe_type, 256, "ft4232"); + else if (desc.idProduct == 0x6001) + snprintf(probe_type, 256, "ft2232RL"); + else if (desc.idProduct == 0x6014) + snprintf(probe_type, 256, "ft232H"); + else if (desc.idProduct == 0x6015) + snprintf(probe_type, 256, "ft231X"); + else + snprintf(probe_type, 256, "unknown FTDI"); + found = true; + } else { + // FIXME: DFU device can't be detected here + for (auto b = cable_list.begin(); b != cable_list.end(); b++) { + cable_t *c = &(*b).second; + if (c->vid == desc.idVendor && c->vid == desc.idProduct) { + snprintf(probe_type, 256, "%s", (*b).first.c_str()); + found = true; + } + } + } + + if (!found) + continue; + + int ret = libusb_open(usb_dev, &handle); + + uint8_t iproduct[200]; + uint8_t iserial[200]; + uint8_t imanufacturer[200]; + ret = libusb_get_string_descriptor_ascii(handle, + desc.iProduct, iproduct, 200); + if (ret < 0) + snprintf((char*)iproduct, 200, "none"); + ret = libusb_get_string_descriptor_ascii(handle, + desc.iManufacturer, imanufacturer, 200); + if (ret < 0) + snprintf((char*)imanufacturer, 200, "none"); + ret = libusb_get_string_descriptor_ascii(handle, + desc.iSerialNumber, iserial, 200); + if (ret < 0) + snprintf((char*)iserial, 200, "none"); + uint8_t bus_addr = libusb_get_bus_number(usb_dev); + uint8_t dev_addr = libusb_get_device_address(usb_dev); + + snprintf(mess, 1024, "%03d %03d 0x%04x:0x%04x %-15s %-12s %-20s %s", + bus_addr, dev_addr, + desc.idVendor, desc.idProduct, + probe_type, imanufacturer, iserial, iproduct); + + printInfo(mess); + + libusb_close(handle); + } + + libusb_free_device_list(dev_list, 1); + free(mess); + + return true; +} diff --git a/src/libusb_ll.hpp b/src/libusb_ll.hpp new file mode 100644 index 0000000..7cb8479 --- /dev/null +++ b/src/libusb_ll.hpp @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (c) 2022 Gwenhael Goavec-Merou + */ + +#ifndef SRC_LIBUSB_LL_HPP_ +#define SRC_LIBUSB_LL_HPP_ + +#include + +class libusb_ll { + public: + explicit libusb_ll(int vid = -1, int pid = -1); + ~libusb_ll(); + + bool scan(); + + private: + struct libusb_context *_usb_ctx; + bool _verbose; +}; + +#endif // SRC_LIBUSB_LL_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 090e032..4cacef9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,7 @@ #include "gowin.hpp" #include "ice40.hpp" #include "lattice.hpp" +#include "libusb_ll.hpp" #include "jtag.hpp" #include "part.hpp" #include "spiFlash.hpp" @@ -40,7 +41,7 @@ using namespace std; struct arguments { int8_t verbose; - bool reset, detect, verify; + bool reset, detect, verify, scan_usb; unsigned int offset; string bit_file; string device; @@ -98,7 +99,7 @@ int main(int argc, char **argv) jtag_pins_conf_t pins_config = {0, 0, 0, 0}; /* command line args. */ - struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, + struct arguments args = {0, false, false, false, false, 0, "", "", "-", "", -1, 0, false, "-", false, false, false, false, Device::PRG_NONE, false, false, false, "", "", "", -1, 0, false, -1, /* vid, pid, index bus_addr, device_addr */ @@ -708,6 +709,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p cxxopts::value(quiet)) ("r,reset", "reset FPGA after operations", cxxopts::value(args->reset)) + ("scan-usb", "scan USB to display connected probes", + cxxopts::value(args->scan_usb)) ("skip-load-bridge", "skip writing bridge to SRAM when in write-flash mode", cxxopts::value(args->skip_load_bridge)) ("skip-reset", "skip resetting the device when in write-flash mode", @@ -860,7 +863,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p args->pin_config = true; } - if (args->list_cables || args->list_boards || args->list_fpga) + if (args->list_cables || args->list_boards || args->list_fpga || + args->scan_usb) args->is_list_command = true; if (args->bit_file.empty() && @@ -931,5 +935,10 @@ void displaySupported(const struct arguments &args) } cout << endl; } + + if (args.scan_usb) { + libusb_ll usb(0,0); + usb.scan(); + } }