Skip to content

Commit 1d7a587

Browse files
committed
Automatically detach ftdi_sio driver
In linux the kernel will automatically bind the ftdi device to the ftdi_sio driver, this prevents the lib D2XX to discover the ftdi. Signed-off-by: Douglas Reis <doreis@lowrisc.org>
1 parent 9fef20f commit 1d7a587

5 files changed

Lines changed: 45 additions & 19 deletions

File tree

app/main.cc

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
using Action = std::function<int()>;
2323

24-
static std::vector<ftdi::DeviceInfo> scan() {
25-
auto result = ftdi::Discovery::scan();
24+
static std::vector<ftdi::DeviceInfo> scan(uint16_t pid = 0x6010) {
25+
auto result = ftdi::Discovery::scan(pid);
2626
if (!result) {
2727
std::cerr << "Error: Failed to communicate with FTDI driver." << std::endl;
2828
exit(0);
@@ -61,11 +61,11 @@ new_flash_command(const std::string& name, const std::string& desc) {
6161
}
6262

6363
static std::optional<ftdi::SpiHost>
64-
handle_flash_command(std::unique_ptr<argparse::ArgumentParser>& cmd) {
64+
handle_flash_command(std::unique_ptr<argparse::ArgumentParser>& cmd, uint16_t pid) {
6565
auto ftdi = cmd->get<std::string>("--ftdi");
6666
auto traces = cmd->get<bool>("--traces");
6767
auto clock = cmd->get<size_t>("--clock");
68-
auto devices = scan();
68+
auto devices = scan(pid);
6969
auto filtered = ftdi::DeviceInfo::filter_by_description(devices, ftdi);
7070
if (filtered.empty()) {
7171
std::print("No {} ftdi found.\n", ftdi);
@@ -81,9 +81,9 @@ handle_flash_command(std::unique_ptr<argparse::ArgumentParser>& cmd) {
8181
}
8282

8383
static std::optional<ftdi::Gpio>
84-
handle_gpio_command(std::unique_ptr<argparse::ArgumentParser>& cmd) {
84+
handle_gpio_command(std::unique_ptr<argparse::ArgumentParser>& cmd, uint16_t pid) {
8585
auto ftdi_filter = cmd->get<std::string>("--ftdi");
86-
auto devices = scan();
86+
auto devices = scan(pid);
8787
auto filtered = ftdi::DeviceInfo::filter_by_description(devices, ftdi_filter);
8888
if (filtered.empty()) {
8989
std::print("No {} ftdi found.\n", ftdi_filter);
@@ -100,13 +100,20 @@ int main(int argc, char* argv[]) {
100100
std::map<std::string, Action> commands;
101101

102102
argparse::ArgumentParser program("ftditool");
103+
program.add_argument("--pid")
104+
.default_value(std::uint16_t{0x6010})
105+
.help(
106+
"The usb product id, in case the ftdi_sio driver needs to be detached. Defaults to "
107+
"FT2232H")
108+
.scan<'x', std::uint16_t>();
103109

104110
argparse::ArgumentParser list_devices_cmd("list-devices");
105111
list_devices_cmd.add_description("List FTDI devices.");
106112
program.add_subparser(list_devices_cmd);
107113
commands["list-devices"] = [&]() -> int {
114+
auto pid = program.get<uint16_t>("--pid");
108115
auto idx = 0;
109-
for (auto device : scan()) {
116+
for (auto device : scan(pid)) {
110117
std::print("{}: {}\n", idx++, device);
111118
}
112119
return 0;
@@ -115,7 +122,8 @@ int main(int argc, char* argv[]) {
115122
auto jedec_cmd = new_flash_command("jedec", "Read the JEDEC identifier.");
116123
program.add_subparser(*jedec_cmd);
117124
commands["jedec"] = [&]() -> int {
118-
auto spih = handle_flash_command(jedec_cmd);
125+
auto pid = program.get<uint16_t>("--pid");
126+
auto spih = handle_flash_command(jedec_cmd, pid);
119127
commands::ReadJedec(flash::Generic(*spih)).run();
120128
spih->close();
121129
return 0;
@@ -124,7 +132,8 @@ int main(int argc, char* argv[]) {
124132
auto sfdp_cmd = new_flash_command("sfdp", "Read serial flash description.");
125133
program.add_subparser(*sfdp_cmd);
126134
commands["sfdp"] = [&]() -> int {
127-
auto spih = handle_flash_command(sfdp_cmd);
135+
auto pid = program.get<uint16_t>("--pid");
136+
auto spih = handle_flash_command(sfdp_cmd, pid);
128137
commands::ReadSfdp(flash::Generic(*spih)).run();
129138
spih->close();
130139
return 0;
@@ -134,8 +143,9 @@ int main(int argc, char* argv[]) {
134143
read_page_cmd->add_argument("--addr").help("The page address").scan<'x', std::size_t>();
135144
program.add_subparser(*read_page_cmd);
136145
commands["read-page"] = [&]() -> int {
146+
auto pid = program.get<uint16_t>("--pid");
137147
auto addr = read_page_cmd->get<std::size_t>("--addr");
138-
auto spih = handle_flash_command(read_page_cmd);
148+
auto spih = handle_flash_command(read_page_cmd, pid);
139149
commands::ReadPage(flash::Generic(*spih), addr).run();
140150
spih->close();
141151
return 0;
@@ -150,9 +160,10 @@ int main(int argc, char* argv[]) {
150160
test_page_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true);
151161
program.add_subparser(*test_page_cmd);
152162
commands["test-page"] = [&]() -> int {
163+
auto pid = program.get<uint16_t>("--pid");
153164
auto addr = test_page_cmd->get<std::size_t>("--addr");
154165
auto quad = test_page_cmd->get<bool>("--quad");
155-
auto spih = handle_flash_command(test_page_cmd);
166+
auto spih = handle_flash_command(test_page_cmd, pid);
156167
commands::TestPage(flash::Generic(*spih), addr, quad).run();
157168

158169
spih->close();
@@ -169,10 +180,11 @@ int main(int argc, char* argv[]) {
169180
load_file_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true);
170181
program.add_subparser(*load_file_cmd);
171182
commands["load-file"] = [&]() -> int {
183+
auto pid = program.get<uint16_t>("--pid");
172184
auto filename = load_file_cmd->get<std::string>("filename");
173185
auto addr = load_file_cmd->get<std::size_t>("--addr");
174186
auto quad = load_file_cmd->get<bool>("--quad");
175-
auto spih = handle_flash_command(load_file_cmd);
187+
auto spih = handle_flash_command(load_file_cmd, pid);
176188
commands::LoadFile(flash::Generic(*spih), filename, addr, false, quad).run();
177189

178190
spih->close();
@@ -192,10 +204,11 @@ int main(int argc, char* argv[]) {
192204
.implicit_value(true);
193205
program.add_subparser(*verify_file_cmd);
194206
commands["verify-file"] = [&]() -> int {
207+
auto pid = program.get<uint16_t>("--pid");
195208
auto filename = verify_file_cmd->get<std::string>("filename");
196209
auto addr = verify_file_cmd->get<std::size_t>("--addr");
197210
auto quad = verify_file_cmd->get<bool>("--quad");
198-
auto spih = handle_flash_command(verify_file_cmd);
211+
auto spih = handle_flash_command(verify_file_cmd, pid);
199212
commands::VerifyFile(flash::Generic(*spih), filename, addr, quad).run();
200213

201214
spih->close();
@@ -212,10 +225,11 @@ int main(int argc, char* argv[]) {
212225
bootstrap_cmd->add_argument("--quad").help("Use qSPI").default_value(false).implicit_value(true);
213226
program.add_subparser(*bootstrap_cmd);
214227
commands["bootstrap"] = [&]() -> int {
228+
auto pid = program.get<uint16_t>("--pid");
215229
auto filename = bootstrap_cmd->get<std::string>("filename");
216230
auto addr = bootstrap_cmd->get<std::size_t>("--addr");
217231
auto quad = bootstrap_cmd->get<bool>("--quad");
218-
auto spih = handle_flash_command(bootstrap_cmd);
232+
auto spih = handle_flash_command(bootstrap_cmd, pid);
219233
commands::LoadFile(flash::Generic(*spih), filename, addr, true, quad).run();
220234

221235
spih->close();
@@ -227,9 +241,10 @@ int main(int argc, char* argv[]) {
227241
gpio_write_cmd->add_argument("value").help("Value to write (0 or 1)").required().scan<'d', int>();
228242
program.add_subparser(*gpio_write_cmd);
229243
commands["gpio-write"] = [&]() -> int {
244+
auto pid = program.get<uint16_t>("--pid");
230245
auto pin = static_cast<uint8_t>(gpio_write_cmd->get<int>("pin"));
231246
auto value = gpio_write_cmd->get<int>("value") != 0;
232-
auto gpio = handle_gpio_command(gpio_write_cmd);
247+
auto gpio = handle_gpio_command(gpio_write_cmd, pid);
233248
commands::GpioWrite(*gpio, pin, value).run();
234249
gpio->close();
235250
return 0;

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
ft4222
4343
libmpsse
4444
];
45-
buildInputs = [ft4222 libmpsse ftd2xx];
45+
buildInputs = with pkgs; [ft4222 libmpsse ftd2xx libusb1 systemd];
4646
shellHook = ''
4747
# Setting LD_LIBRARY_PATH for libftd2xx
4848
export LD_LIBRARY_PATH="${ftd2xx}/lib:$LD_LIBRARY_PATH"

lib/ftdi/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ target_sources(ftdipp
88
PRIVATE
99
spi_host.cc
1010
gpio.cc
11+
libusb.cc
1112
PUBLIC
1213
FILE_SET HEADERS
1314
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
@@ -16,6 +17,7 @@ target_sources(ftdipp
1617
spi_host.hh
1718
gpio.hh
1819
log.hh
20+
libusb.hh
1921
)
2022

2123
target_include_directories(ftdipp
@@ -25,7 +27,8 @@ target_include_directories(ftdipp
2527
)
2628

2729
target_link_libraries(ftdipp
28-
PUBLIC magic_enum::magic_enum embeddedpp mpsse ft4222
30+
PUBLIC magic_enum::magic_enum embeddedpp mpsse ft4222
31+
PRIVATE usb-1.0 udev
2932
)
3033
target_compile_options(ftdipp PRIVATE "-fno-exceptions")
3134

lib/ftdi/ftdi.hh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
#pragma once
66

77
#include "ftd2xx.h"
8-
#include <cstdint>
98
#include <optional>
109
#include <vector>
1110
#include <iostream>
1211
#include "device_info.hh"
12+
#include "libusb.hh"
1313

1414
namespace ftdi {
1515

@@ -19,7 +19,11 @@ class Discovery {
1919
* @brief Scans for all connected FTDI devices.
2020
* @return A vector of devices if successful, or std::nullopt if the driver call failed.
2121
*/
22-
static std::optional<std::vector<DeviceInfo>> scan() {
22+
23+
static std::optional<std::vector<DeviceInfo>> scan(uint16_t pid) {
24+
// Detach ftdi_sio (if present) so D2XX can enumerate the device.
25+
detach_ftdi_sio(pid);
26+
2327
DWORD num_devs = 0;
2428

2529
// 1. Get the number of devices

nix/ftditool.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
argparse,
1313
magic-enum,
1414
picosha2,
15+
libusb1,
16+
systemd,
1517
makeWrapper,
1618
}:
1719
stdenv.mkDerivation {
@@ -33,6 +35,8 @@ stdenv.mkDerivation {
3335
magic-enum
3436
picosha2
3537
ftd2xx
38+
libusb1
39+
systemd
3640
];
3741

3842
cmakeFlags = [

0 commit comments

Comments
 (0)