Implement USB mass storage and batch OHCI bulk transfers

This commit is contained in:
Aaron committed 2026-10-31 20:36:52 +00:00
1 parent c0c56a9c84
commit c28b9dd77f
7 files changed
+919 -146

No files matched your search

+24 -6
View File
@@ -658,6 +658,7 @@ begin
{ Step 2: Create device at address 0 }
dev := PUSBDevice(kalloc(sizeof(TUSBDevice)));
if dev = nil then begin pop_trace; exit; end;
dev^.Address := 0;
dev^.Speed := speed;
dev^.MaxPacket0 := 8; { Default, will be updated from descriptor }
@@ -667,6 +668,8 @@ begin
dev^.ParentPort := parentPort;
dev^.NumEndpoints := 0;
dev^.Configured := false;
dev^.InterfaceNumber := 0;
dev^.InterfaceCount := 0;
dev^.fnDisconnect := nil;
{ Step 3: Get first 8 bytes of device descriptor to learn MaxPacketSize0 }
@@ -730,7 +733,14 @@ begin
end;
totalLen := cfgDesc.wTotalLength;
if totalLen < sizeof(TUSBConfigDescriptor) then begin
kfree(void(dev));
pop_trace;
exit;
end;
dev^.InterfaceCount := cfgDesc.bNumInterfaces;
cfgBuf := Pointer(kalloc(totalLen));
if cfgBuf = nil then begin kfree(void(dev)); pop_trace; exit; end;
status := usb_get_descriptor(dev, USB_DESC_CONFIGURATION, 0, cfgBuf, totalLen);
if status <> tsSuccess then begin
@@ -744,12 +754,14 @@ begin
{ Step 7: Parse interface and endpoint descriptors }
offset := sizeof(TUSBConfigDescriptor);
dev^.NumEndpoints := 0;
while offset < totalLen do begin
while offset + 2 <= totalLen do begin
{ Read descriptor length and type }
if PUint8(uint32(cfgBuf) + offset)^ = 0 then break; { Safety: zero-length = corrupt }
if PUint8(uint32(cfgBuf) + offset)^ < 2 then break;
if offset + PUint8(uint32(cfgBuf) + offset)^ > totalLen then break;
if PUint8(uint32(cfgBuf) + offset + 1)^ = USB_DESC_ENDPOINT then begin
if dev^.NumEndpoints < USB_MAX_ENDPOINTS then begin
if (PUint8(uint32(cfgBuf) + offset)^ >= sizeof(TUSBEndpointDescriptor)) and
(dev^.NumEndpoints < USB_MAX_ENDPOINTS) then begin
epDesc := PUSBEndpointDescriptor(uint32(cfgBuf) + offset);
dev^.Endpoints[dev^.NumEndpoints].Address := usb_ep_number(epDesc^.bEndpointAddress);
dev^.Endpoints[dev^.NumEndpoints].Direction := usb_ep_direction(epDesc^.bEndpointAddress);
@@ -780,16 +792,22 @@ begin
{ Find the first interface descriptor for class/subclass/protocol }
offset := sizeof(TUSBConfigDescriptor);
ifDesc := nil;
while offset < totalLen do begin
if PUint8(uint32(cfgBuf) + offset)^ = 0 then break;
if PUint8(uint32(cfgBuf) + offset + 1)^ = USB_DESC_INTERFACE then begin
while offset + 2 <= totalLen do begin
if PUint8(uint32(cfgBuf) + offset)^ < 2 then break;
if offset + PUint8(uint32(cfgBuf) + offset)^ > totalLen then break;
if (PUint8(uint32(cfgBuf) + offset + 1)^ = USB_DESC_INTERFACE) and
(PUint8(uint32(cfgBuf) + offset)^ >= sizeof(TUSBInterfaceDescriptor)) then begin
ifDesc := PUSBInterfaceDescriptor(uint32(cfgBuf) + offset);
dev^.InterfaceNumber := ifDesc^.bInterfaceNumber;
break;
end;
offset := offset + PUint8(uint32(cfgBuf) + offset)^;
end;
DevID := PDeviceIdentifier(kalloc(sizeof(TDeviceIdentifier)));
if DevID = nil then begin
kfree(void(cfgBuf)); kfree(void(dev)); pop_trace; exit;
end;
DevID^.Bus := biUSB;
DevID^.id0 := (uint32(devDesc.idVendor) SHL 16) OR devDesc.idProduct;
DevID^.id1 := devDesc.bDeviceClass;
+26 -7
View File
@@ -963,6 +963,8 @@ end;
{ ========================= Submit Transfer ========================= }
procedure ehci_free_qtd_chain(first : PEHCI_qTD); forward;
function ehci_submit_control(hc : PUSBHCDriver; transfer : PUSBTransfer) : boolean;
var
priv : PEHCI_PrivData;
@@ -1004,7 +1006,7 @@ begin
{ SETUP qTD }
qtd := ehci_alloc_qtd;
if qtd = nil then begin pop_trace; exit; end;
if qtd = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
firstqTD := qtd;
qtd^.Token := ehci_make_qtd_token(EHCI_QTD_PID_SETUP, false, 8, false, 3);
ehci_fill_qtd_buffers(qtd, @transfer^.Setup, 8);
@@ -1021,7 +1023,7 @@ begin
while remaining > 0 do begin
qtd := ehci_alloc_qtd;
if qtd = nil then begin pop_trace; exit; end;
if qtd = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
if remaining > maxPkt then
pktLen := maxPkt
@@ -1034,6 +1036,7 @@ begin
pid := EHCI_QTD_PID_OUT;
qtd^.Token := ehci_make_qtd_token(pid, toggle, pktLen, false, 3);
qtd^.SWPad0 := pktLen; { Original data length, excluding SETUP/status }
ehci_fill_qtd_buffers(qtd, Pointer(uint32(transfer^.Buffer) + offset), pktLen);
qtd^.NextqTD := EHCI_QTD_T;
qtd^.AltNextqTD := EHCI_QTD_T;
@@ -1052,7 +1055,7 @@ begin
{ STATUS qTD (opposite direction, DATA1) }
qtd := ehci_alloc_qtd;
if qtd = nil then begin pop_trace; exit; end;
if qtd = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
if (transfer^.Setup.bmRequestType AND $80) <> 0 then
pid := EHCI_QTD_PID_OUT
@@ -1070,7 +1073,7 @@ begin
{ Build QH }
qh := ehci_alloc_qh;
if qh = nil then begin pop_trace; exit; end;
if qh = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
qh^.EPChars := ehci_make_qh_epchars(devAddr, 0, speedBits, maxPkt,
true, false, isCtrlEP, 4);
@@ -1152,7 +1155,7 @@ begin
repeat
qtd := ehci_alloc_qtd;
if qtd = nil then begin pop_trace; exit; end;
if qtd = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
if firstqTD = nil then firstqTD := qtd;
@@ -1164,6 +1167,7 @@ begin
pktLen := 0;
qtd^.Token := ehci_make_qtd_token(pid, toggle, pktLen, false, 3);
qtd^.SWPad0 := pktLen; { Original data length, excluding SETUP/status }
if pktLen > 0 then
ehci_fill_qtd_buffers(qtd, Pointer(uint32(transfer^.Buffer) + offset), pktLen);
qtd^.NextqTD := EHCI_QTD_T;
@@ -1200,7 +1204,7 @@ begin
{ Build QH }
qh := ehci_alloc_qh;
if qh = nil then begin pop_trace; exit; end;
if qh = nil then begin ehci_free_qtd_chain(firstqTD); pop_trace; exit; end;
qh^.EPChars := ehci_make_qh_epchars(devAddr, epNum, speedBits, maxPkt,
true, false, false, 4);
@@ -1297,6 +1301,11 @@ begin
ehci_transfer_done := true;
exit;
end;
if (qh^.SWTransfer <> nil) and
(PUSBTransfer(qh^.SWTransfer)^.PipeType = ptBulk) and
(((qtd^.Token SHR 16) AND $7FFF) <> 0) then begin
ehci_transfer_done := true; exit;
end;
qtd := qtd^.SWNext;
end;
ehci_transfer_done := true;
@@ -1385,6 +1394,8 @@ var
transfer : PUSBTransfer;
head : PEHCI_QH;
listIdx : uint32;
qtd : PEHCI_qTD;
residual : uint32;
begin
if (hc = nil) or (hc^.PrivData = nil) then exit;
priv := PEHCI_PrivData(hc^.PrivData);
@@ -1422,7 +1433,15 @@ begin
if transfer^.Status = tsInProgress then begin
if ehci_transfer_done(qh) then begin
transfer^.Status := ehci_transfer_status(qh);
transfer^.ActualLen := transfer^.BufferLen;
transfer^.ActualLen := 0;
qtd := qh^.SWFirstqTD;
while qtd <> nil do begin
if (qtd^.Token AND EHCI_QTD_STS_ACTIVE) <> 0 then break;
residual := (qtd^.Token SHR 16) AND $7FFF;
if (qtd^.SWPad0 > 0) and (residual <= qtd^.SWPad0) then
inc(transfer^.ActualLen, qtd^.SWPad0 - residual);
qtd := qtd^.SWNext;
end;
{ Remove QH from schedule and free qTD chain }
if listIdx = 0 then
ehci_remove_async_qh(priv, qh)
File diff suppressed because it is too large. Load diff
@@ -249,6 +249,8 @@ type
Endpoints : array[0..USB_MAX_ENDPOINTS-1] of TUSBEndpoint;
NumEndpoints : uint8;
Configured : boolean;
InterfaceNumber : uint8; { First interface, alternate setting zero }
InterfaceCount : uint8; { Class drivers may reject composite devices }
fnDisconnect : TUSBDisconnectCallback; { Called before device is freed on unplug }
end;
File diff suppressed because it is too large. Load diff
+2
View File
@@ -37,6 +37,7 @@ uses
driver.storage.metatest,
driver.storage.perftest,
driver.storage.ctl.ahci,
driver.storage.ctl.usb,
core.enc.fnv1a,
core.enc.djb2,
core.ds.bloom,
@@ -76,6 +77,7 @@ begin
driver.storage.metatest.UnitTest;
driver.storage.perftest.UnitTest;
driver.storage.ctl.ahci.UnitTest;
driver.storage.ctl.usb.UnitTest;
core.enc.fnv1a.UnitTest;
core.enc.djb2.UnitTest;
core.ds.bloom.UnitTest;