Skip to content

Commit 48aca08

Browse files
committed
[ftdi] Add function to detach ftdi_sio driver
This function was written with the help of claude code. Signed-off-by: Douglas Reis <doreis@lowrisc.org>
1 parent 84307b6 commit 48aca08

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

lib/ftdi/kernel_driver.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright lowRISC contributors.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#include "kernel_driver.hh"
6+
7+
#include <libudev.h>
8+
#include <libusb-1.0/libusb.h>
9+
10+
#include <iostream>
11+
12+
namespace ftdi {
13+
14+
enum { kFtdiVid = 0x0403 };
15+
16+
// Use libusb to temporarily detach ftdi_sio from every interface of
17+
// every FTDI USB device. The kernel driver is re-attached automatically when
18+
// the D2XX / libft4222 handle is closed.
19+
void detach_ftdi_kernel_drivers(uint16_t pid) {
20+
libusb_context* ctx = nullptr;
21+
if (libusb_init(&ctx) != LIBUSB_SUCCESS) {
22+
std::cerr << "libusb_init failed\n";
23+
return;
24+
}
25+
26+
libusb_device** devs = nullptr;
27+
ssize_t cnt = libusb_get_device_list(ctx, &devs);
28+
if (cnt < 0) {
29+
libusb_exit(ctx);
30+
return;
31+
}
32+
33+
for (ssize_t i = 0; i < cnt; i++) {
34+
libusb_device_descriptor desc{};
35+
if (libusb_get_device_descriptor(devs[i], &desc) != LIBUSB_SUCCESS) continue;
36+
if (desc.idVendor != kFtdiVid || desc.idProduct != pid) continue;
37+
38+
libusb_device_handle* handle = nullptr;
39+
if (libusb_open(devs[i], &handle) != LIBUSB_SUCCESS) continue;
40+
41+
libusb_config_descriptor* config = nullptr;
42+
if (libusb_get_active_config_descriptor(devs[i], &config) == LIBUSB_SUCCESS) {
43+
for (uint8_t j = 0; j < config->bNumInterfaces; j++) {
44+
if (libusb_kernel_driver_active(handle, j) != 1) continue;
45+
int ret = libusb_detach_kernel_driver(handle, j);
46+
if (ret != LIBUSB_SUCCESS) {
47+
std::cerr << "Failed to detach kernel driver on interface " << (int)j << ": "
48+
<< libusb_error_name(ret) << "\n";
49+
}
50+
}
51+
libusb_free_config_descriptor(config);
52+
}
53+
54+
libusb_close(handle);
55+
}
56+
57+
libusb_free_device_list(devs, 1);
58+
libusb_exit(ctx);
59+
}
60+
61+
} // namespace ftdi

lib/ftdi/kernel_driver.hh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright lowRISC contributors.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#pragma once
6+
7+
#include <cstdint>
8+
#include <format>
9+
#include <string>
10+
#include <vector>
11+
12+
namespace ftdi {
13+
14+
// Option A: Detach ftdi_sio (or any kernel driver) from all FTDI USB interfaces
15+
// using libusb. This allows the D2XX library to claim the device afterwards.
16+
// Requires write access to the USB device files — install 99-ftditool.rules.
17+
void detach_ftdi_kernel_drivers(uint16_t pid);
18+
19+
} // namespace ftdi

0 commit comments

Comments
 (0)