fix: move RTL-SDR to userspace

This commit is contained in:
2026-08-29 10:02:32 +02:00
parent b1f1cfe32b
commit 5cd5c2e6be
35 changed files with 1922 additions and 1592 deletions
+58 -16
View File
@@ -10,7 +10,6 @@
#include "HidMouse.hpp"
#include "MassStorage.hpp"
#include "Bluetooth/Bluetooth.hpp"
#include "Radio/RtlSdr.hpp"
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include <Memory/HHDM.hpp>
@@ -351,11 +350,6 @@ namespace Drivers::USB::UsbDevice {
bool foundBulkOut = false;
uint16_t hidReportDescLen = 0;
// RTL-SDR dongles are vendor-class (0xFF) devices identified by VID:PID.
// They expose a single bulk-IN endpoint that streams raw I/Q samples;
// treat them like the other bulk-capable class drivers below.
bool foundRadio = Drivers::USB::Radio::IsRtlSdr(devDesc.idVendor, devDesc.idProduct);
while (offset + 2 <= totalLen) {
uint8_t len = cfgBuf[offset];
uint8_t type = cfgBuf[offset + 1];
@@ -423,8 +417,8 @@ namespace Drivers::USB::UsbDevice {
foundEp = true;
}
// Bluetooth, Mass Storage and RTL-SDR bulk endpoints
if (foundBt || currentMsc || foundRadio) {
// Bulk endpoints needed by in-kernel Bluetooth and storage drivers.
if (foundBt || currentMsc) {
if (isIn && xferType == EP_XFER_INTERRUPT && !foundEp) {
// HCI event pipe (interrupt IN)
dev->InterruptEpNum = ep->bEndpointAddress & 0x0F;
@@ -457,6 +451,51 @@ namespace Drivers::USB::UsbDevice {
foundBt = true;
}
// No in-kernel class driver recognized this device. Preserve the first
// interface and its bulk endpoints so a userspace driver can claim it.
// The xHCI slot model currently stores one interface; a future model
// can retain every alternate/interface without changing the userspace
// claim ABI, which already names the interface number explicitly.
bool knownInterface = foundBt || foundMsc ||
dev->InterfaceClass == CLASS_HID;
if (!knownInterface) {
bool inFirstInterface = false;
bool haveFirstInterface = false;
offset = 0;
while (offset + 2 <= totalLen) {
uint8_t len = cfgBuf[offset];
uint8_t type = cfgBuf[offset + 1];
if (len == 0 || offset + len > totalLen) break;
if (type == DESC_INTERFACE &&
offset + sizeof(InterfaceDescriptor) <= totalLen) {
if (haveFirstInterface) break;
auto* iface = (InterfaceDescriptor*)&cfgBuf[offset];
dev->InterfaceClass = iface->bInterfaceClass;
dev->InterfaceSubClass = iface->bInterfaceSubClass;
dev->InterfaceProtocol = iface->bInterfaceProtocol;
dev->InterfaceNumber = iface->bInterfaceNumber;
haveFirstInterface = true;
inFirstInterface = true;
} else if (inFirstInterface && type == DESC_ENDPOINT &&
offset + sizeof(EndpointDescriptor) <= totalLen) {
auto* ep = (EndpointDescriptor*)&cfgBuf[offset];
uint8_t xferType = ep->bmAttributes & EP_XFER_TYPE_MASK;
bool isIn = (ep->bEndpointAddress & EP_DIR_IN) != 0;
if (xferType == EP_XFER_BULK && isIn && !foundBulkIn) {
dev->BulkInEpNum = ep->bEndpointAddress & 0x0F;
dev->BulkInMaxPacket = ep->wMaxPacketSize & 0x7FF;
foundBulkIn = true;
} else if (xferType == EP_XFER_BULK && !isIn && !foundBulkOut) {
dev->BulkOutEpNum = ep->bEndpointAddress & 0x0F;
dev->BulkOutMaxPacket = ep->wMaxPacketSize & 0x7FF;
foundBulkOut = true;
}
}
offset += len;
}
}
// -----------------------------------------------------------------
// Step 8: SET_CONFIGURATION
// -----------------------------------------------------------------
@@ -657,15 +696,20 @@ namespace Drivers::USB::UsbDevice {
// -----------------------------------------------------------------
// Step 13: Register with the appropriate class driver
// -----------------------------------------------------------------
if (dev->InterfaceClass == CLASS_HID && dev->InterfaceProtocol == PROTOCOL_KEYBOARD) {
if (foundEp && dev->InterfaceClass == CLASS_HID &&
dev->InterfaceProtocol == PROTOCOL_KEYBOARD) {
dev->KernelDriverBound = true;
HidKeyboard::RegisterDevice(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId << ": HID Boot Keyboard";
} else if (dev->InterfaceClass == CLASS_HID && dev->InterfaceProtocol == PROTOCOL_MOUSE) {
} else if (foundEp && dev->InterfaceClass == CLASS_HID &&
dev->InterfaceProtocol == PROTOCOL_MOUSE) {
dev->KernelDriverBound = true;
HidMouse::RegisterDevice(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId << ": HID Boot Mouse";
} else if (dev->InterfaceClass == CLASS_WIRELESS &&
dev->InterfaceSubClass == SUBCLASS_RF &&
dev->InterfaceProtocol == PROTOCOL_BLUETOOTH) {
dev->KernelDriverBound = true;
Bluetooth::RegisterAdapter(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId << ": Bluetooth Adapter"
<< " VID:" << base::hex << (uint64_t)dev->VendorId
@@ -674,15 +718,10 @@ namespace Drivers::USB::UsbDevice {
dev->InterfaceSubClass == SUBCLASS_SCSI &&
dev->InterfaceProtocol == PROTOCOL_BULK_ONLY &&
foundMsc && foundBulkIn && foundBulkOut) {
dev->KernelDriverBound = true;
MassStorage::RegisterDevice(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId
<< ": USB Mass Storage";
} else if (foundRadio && foundBulkIn) {
Drivers::USB::Radio::RegisterDevice(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId
<< ": RTL-SDR receiver"
<< " VID:" << base::hex << (uint64_t)dev->VendorId
<< " PID:" << (uint64_t)dev->ProductId << base::dec;
} else if (foundEp) {
KernelLogStream(INFO, "USB") << "Slot " << (uint64_t)slotId
<< ": USB device, class=" << (uint64_t)dev->InterfaceClass
@@ -692,6 +731,9 @@ namespace Drivers::USB::UsbDevice {
<< ": Non-HID device, class=" << (uint64_t)devDesc.bDeviceClass;
}
// Publish to userspace only after endpoint configuration and kernel
// class-driver binding decisions are complete.
dev->Ready = true;
return slotId;
}