feat: support for USB mass storage devices, hotplugging

This commit is contained in:
2026-05-18 17:47:12 +02:00
parent d340e01e56
commit c20579afd3
36 changed files with 1537 additions and 130 deletions
+32 -8
View File
@@ -8,6 +8,7 @@
#include "Xhci.hpp"
#include "HidKeyboard.hpp"
#include "HidMouse.hpp"
#include "MassStorage.hpp"
#include "Bluetooth/Bluetooth.hpp"
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -129,6 +130,7 @@ namespace Drivers::USB::UsbDevice {
// Step 2: Allocate device output context and set DCBAA entry
// -----------------------------------------------------------------
auto* dev = Xhci::GetDevice(slotId);
*dev = {};
dev->Active = true;
dev->PortId = portId;
dev->Speed = speed;
@@ -341,6 +343,8 @@ namespace Drivers::USB::UsbDevice {
uint16_t offset = 0;
bool foundHid = false;
bool foundBt = false;
bool foundMsc = false;
bool currentMsc = false;
bool foundEp = false;
bool foundBulkIn = false;
bool foundBulkOut = false;
@@ -356,6 +360,7 @@ namespace Drivers::USB::UsbDevice {
// Reset at each new interface boundary
foundHid = false;
foundBt = false;
currentMsc = false;
if (!foundEp &&
iface->bInterfaceClass == CLASS_HID &&
@@ -363,6 +368,7 @@ namespace Drivers::USB::UsbDevice {
dev->InterfaceClass = iface->bInterfaceClass;
dev->InterfaceSubClass = iface->bInterfaceSubClass;
dev->InterfaceProtocol = iface->bInterfaceProtocol;
dev->InterfaceNumber = iface->bInterfaceNumber;
foundHid = true;
}
@@ -374,9 +380,22 @@ namespace Drivers::USB::UsbDevice {
dev->InterfaceClass = iface->bInterfaceClass;
dev->InterfaceSubClass = iface->bInterfaceSubClass;
dev->InterfaceProtocol = iface->bInterfaceProtocol;
dev->InterfaceNumber = iface->bInterfaceNumber;
}
foundBt = true;
}
// USB Mass Storage Bulk-Only Transport with SCSI transparent commands
if (iface->bInterfaceClass == CLASS_MASS_STORAGE &&
iface->bInterfaceSubClass == SUBCLASS_SCSI &&
iface->bInterfaceProtocol == PROTOCOL_BULK_ONLY) {
dev->InterfaceClass = iface->bInterfaceClass;
dev->InterfaceSubClass = iface->bInterfaceSubClass;
dev->InterfaceProtocol = iface->bInterfaceProtocol;
dev->InterfaceNumber = iface->bInterfaceNumber;
currentMsc = true;
foundMsc = true;
}
}
// HID descriptor (0x21): extract report descriptor length
@@ -398,8 +417,8 @@ namespace Drivers::USB::UsbDevice {
foundEp = true;
}
// Bluetooth endpoints
if (foundBt) {
// Bluetooth and Mass Storage bulk endpoints
if (foundBt || currentMsc) {
if (isIn && xferType == EP_XFER_INTERRUPT && !foundEp) {
// HCI event pipe (interrupt IN)
dev->InterruptEpNum = ep->bEndpointAddress & 0x0F;
@@ -407,12 +426,10 @@ namespace Drivers::USB::UsbDevice {
dev->InterruptInterval = ep->bInterval;
foundEp = true;
} else if (isIn && xferType == EP_XFER_BULK && !foundBulkIn) {
// ACL data IN pipe (bulk IN)
dev->BulkInEpNum = ep->bEndpointAddress & 0x0F;
dev->BulkInMaxPacket = ep->wMaxPacketSize & 0x7FF;
foundBulkIn = true;
} else if (!isIn && xferType == EP_XFER_BULK && !foundBulkOut) {
// ACL data OUT pipe (bulk OUT)
dev->BulkOutEpNum = ep->bEndpointAddress & 0x0F;
dev->BulkOutMaxPacket = ep->wMaxPacketSize & 0x7FF;
foundBulkOut = true;
@@ -585,7 +602,7 @@ namespace Drivers::USB::UsbDevice {
// HidMouse parses the HID Report Descriptor to handle variable formats.
if (foundEp && dev->InterfaceClass == CLASS_HID && dev->InterfaceProtocol == PROTOCOL_KEYBOARD) {
cc = Xhci::ControlTransfer(slotId, REQTYPE_CLASS_IFACE, REQ_SET_PROTOCOL,
0, 0, 0, nullptr, false);
0, dev->InterfaceNumber, 0, nullptr, false);
if (cc != Xhci::CC_SUCCESS) {
KernelLogStream(WARNING, "USB") << "SET_PROTOCOL(Boot) failed, cc=" << (uint64_t)cc;
// Non-fatal: some devices only support boot protocol anyway
@@ -601,7 +618,7 @@ namespace Drivers::USB::UsbDevice {
if (rdLen > 256) rdLen = 256;
cc = Xhci::ControlTransfer(slotId, REQTYPE_STD_IFACE_IN, REQ_GET_DESCRIPTOR,
(DESC_HID_REPORT << 8), 0, rdLen,
(DESC_HID_REPORT << 8), dev->InterfaceNumber, rdLen,
rdBuf, true);
if (cc == Xhci::CC_SUCCESS || cc == Xhci::CC_SHORT_PACKET) {
HidMouse::ParseReportDescriptor(rdBuf, rdLen);
@@ -616,7 +633,7 @@ namespace Drivers::USB::UsbDevice {
if (foundEp && dev->InterfaceClass == CLASS_HID && dev->InterfaceProtocol == PROTOCOL_KEYBOARD) {
// wValue upper byte = duration (0 = indefinite), lower byte = report ID
cc = Xhci::ControlTransfer(slotId, REQTYPE_CLASS_IFACE, REQ_SET_IDLE,
(0 << 8), 0, 0, nullptr, false);
(0 << 8), dev->InterfaceNumber, 0, nullptr, false);
if (cc != Xhci::CC_SUCCESS) {
KernelLogStream(WARNING, "USB") << "SET_IDLE(0) failed, cc=" << (uint64_t)cc;
// Non-fatal: not all devices support SET_IDLE
@@ -627,7 +644,7 @@ namespace Drivers::USB::UsbDevice {
// Step 12: Queue first interrupt transfer (HID only)
// Bluetooth manages its own interrupt/bulk transfers via StartEventPipe()
// -----------------------------------------------------------------
if (foundEp && !foundBt) {
if (foundEp && dev->InterfaceClass == CLASS_HID) {
Xhci::QueueInterruptTransfer(slotId);
}
@@ -647,6 +664,13 @@ namespace Drivers::USB::UsbDevice {
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId << ": Bluetooth Adapter"
<< " VID:" << base::hex << (uint64_t)dev->VendorId
<< " PID:" << (uint64_t)dev->ProductId << base::dec;
} else if (dev->InterfaceClass == CLASS_MASS_STORAGE &&
dev->InterfaceSubClass == SUBCLASS_SCSI &&
dev->InterfaceProtocol == PROTOCOL_BULK_ONLY &&
foundMsc && foundBulkIn && foundBulkOut) {
MassStorage::RegisterDevice(slotId);
KernelLogStream(OK, "USB") << "Slot " << (uint64_t)slotId
<< ": USB Mass Storage";
} else if (foundEp) {
KernelLogStream(INFO, "USB") << "Slot " << (uint64_t)slotId
<< ": USB device, class=" << (uint64_t)dev->InterfaceClass