feat: support for USB mass storage devices, hotplugging
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user