diff --git a/src/driver/bus/usb/driver.bus.usb.core.pas b/src/driver/bus/usb/driver.bus.usb.core.pas index 60ff1031..c0181c10 100644 --- a/src/driver/bus/usb/driver.bus.usb.core.pas +++ b/src/driver/bus/usb/driver.bus.usb.core.pas @@ -24,7 +24,7 @@ interface uses driver.bus.usb.types, - core.util, arch.x86.util, + core.util, arch.platform.cpu, arch.platform.diagnostics, memory.heap, core.ds.lists, driver.types, @@ -33,7 +33,7 @@ uses io.syslog, core.strings, io.stdio, - arch.x86.bda; + arch.platform.process; { ========================= HC Management ========================= } @@ -41,7 +41,7 @@ uses Returns the stable heap-allocated pointer to the HC record (not the caller's stack copy). } function register_hc(hc : PUSBHCDriver) : PUSBHCDriver; -{ Unregister a host controller. } +{ Unregister an empty host controller. Remove attached devices first. } procedure unregister_hc(hc : PUSBHCDriver); { Get the number of registered host controllers. } @@ -199,9 +199,14 @@ begin if (hc <> nil) and (HCList <> nil) then begin entry := PUSBHCDriver(LL_Add(HCList)); if entry <> nil then begin - memcpy(uint32(hc), uint32(entry), sizeof(TUSBHCDriver)); + memcpy(PtrUInt(hc), PtrUInt(entry), sizeof(TUSBHCDriver)); { Initialize per-HC device list } entry^.Devices := LL_New(sizeof(PUSBDevice)); + if entry^.Devices = nil then begin + LL_Delete(HCList, LL_Size(HCList) - 1); + pop_trace; + exit; + end; entry^.HotplugArmed := false; entry^.PortChangePending := false; io.syslog.log('driver.bus.usb Core', 'Registered HC: '); @@ -219,15 +224,20 @@ var begin push_trace('driver.bus.usb.core.unregister_hc'); if (hc <> nil) and (HCList <> nil) then begin - for i := 0 to LL_Size(HCList) - 1 do begin - entry := PUSBHCDriver(LL_Get(HCList, i)); - if (entry <> nil) and (entry^.BaseAddr = hc^.BaseAddr) and (entry^.HCType = hc^.HCType) then begin - LL_Delete(HCList, i); - io.syslog.log('driver.bus.usb Core', 'Unregistered HC: '); - io.syslog.writestringln(hc^.Name); - break; + if LL_Size(HCList) > 0 then + for i := 0 to LL_Size(HCList) - 1 do begin + entry := PUSBHCDriver(LL_Get(HCList, i)); + if (entry <> nil) and (entry^.BaseAddr = hc^.BaseAddr) and (entry^.HCType = hc^.HCType) then begin + if entry^.Devices <> nil then begin + if LL_Size(entry^.Devices) <> 0 then break; + LL_Free(entry^.Devices); + end; + io.syslog.log('driver.bus.usb Core', 'Unregistered HC: '); + io.syslog.writestringln(hc^.Name); + LL_Delete(HCList, i); + break; + end; end; - end; end; pop_trace; end; @@ -363,11 +373,11 @@ begin end; { Poll until complete (with real-time timeout: 5 seconds at 1024 Hz) } - polls := arch.x86.bda.Counters.c32; + polls := arch.platform.process.timerTicks; while (transfer.Status = tsInProgress) or (transfer.Status = tsNotStarted) do begin if dev^.HC^.fnPoll <> nil then dev^.HC^.fnPoll(dev^.HC); - if (arch.x86.bda.Counters.c32 - polls) > 5120 then begin + if (arch.platform.process.timerTicks - polls) > 5120 then begin usb_control_msg := tsTimeout; pop_trace; exit; @@ -522,11 +532,11 @@ begin ticks := timeoutMs; if ticks = 0 then ticks := 5120; { default 5 seconds } - startTick := arch.x86.bda.Counters.c32; + startTick := arch.platform.process.timerTicks; while (transfer^.Status = tsInProgress) or (transfer^.Status = tsNotStarted) do begin if dev^.HC^.fnPoll <> nil then dev^.HC^.fnPoll(dev^.HC); - if (arch.x86.bda.Counters.c32 - startTick) > ticks then begin + if (arch.platform.process.timerTicks - startTick) > ticks then begin kfree(void(transfer)); usb_bulk_transfer_wait := tsTimeout; pop_trace; @@ -560,12 +570,12 @@ begin offset := sizeof(TUSBConfigDescriptor); count := 0; while offset < totalLen do begin - bLen := PUint8(uint32(configBuf) + offset)^; + bLen := PUint8(PtrUInt(configBuf) + offset)^; if bLen = 0 then exit; { corrupt } - bType := PUint8(uint32(configBuf) + offset + 1)^; + bType := PUint8(PtrUInt(configBuf) + offset + 1)^; if bType = USB_DESC_INTERFACE then begin if count = index then begin - usb_find_interface_n := PUSBInterfaceDescriptor(uint32(configBuf) + offset); + usb_find_interface_n := PUSBInterfaceDescriptor(PtrUInt(configBuf) + offset); exit; end; inc(count); @@ -584,14 +594,14 @@ begin usb_count_endpoints := 0; if configBuf = nil then exit; { Skip past the interface descriptor itself } - bLen := PUint8(uint32(configBuf) + ifaceOffset)^; + bLen := PUint8(PtrUInt(configBuf) + ifaceOffset)^; if bLen = 0 then exit; offset := ifaceOffset + bLen; count := 0; while offset < totalLen do begin - bLen := PUint8(uint32(configBuf) + offset)^; + bLen := PUint8(PtrUInt(configBuf) + offset)^; if bLen = 0 then break; - bType := PUint8(uint32(configBuf) + offset + 1)^; + bType := PUint8(PtrUInt(configBuf) + offset + 1)^; { Stop at next interface descriptor } if bType = USB_DESC_INTERFACE then break; if bType = USB_DESC_ENDPOINT then @@ -611,18 +621,18 @@ begin usb_find_endpoint := nil; if configBuf = nil then exit; { Skip past the interface descriptor itself } - bLen := PUint8(uint32(configBuf) + ifaceOffset)^; + bLen := PUint8(PtrUInt(configBuf) + ifaceOffset)^; if bLen = 0 then exit; offset := ifaceOffset + bLen; count := 0; while offset < totalLen do begin - bLen := PUint8(uint32(configBuf) + offset)^; + bLen := PUint8(PtrUInt(configBuf) + offset)^; if bLen = 0 then break; - bType := PUint8(uint32(configBuf) + offset + 1)^; + bType := PUint8(PtrUInt(configBuf) + offset + 1)^; if bType = USB_DESC_INTERFACE then break; if bType = USB_DESC_ENDPOINT then begin if count = index then begin - usb_find_endpoint := PUSBEndpointDescriptor(uint32(configBuf) + offset); + usb_find_endpoint := PUSBEndpointDescriptor(PtrUInt(configBuf) + offset); exit; end; inc(count); @@ -651,6 +661,7 @@ var addr : uint8; i : uint32; DevID : PDeviceIdentifier; + deviceSlot: PPUSBDevice; begin push_trace('driver.bus.usb.core.enumerate_device'); enumerate_device := nil; @@ -771,13 +782,13 @@ begin dev^.NumEndpoints := 0; while offset + 2 <= totalLen do begin { Read descriptor length and type } - if PUint8(uint32(cfgBuf) + offset)^ < 2 then break; - if offset + PUint8(uint32(cfgBuf) + offset)^ > totalLen then break; + if PUint8(PtrUInt(cfgBuf) + offset)^ < 2 then break; + if offset + PUint8(PtrUInt(cfgBuf) + offset)^ > totalLen then break; - if PUint8(uint32(cfgBuf) + offset + 1)^ = USB_DESC_ENDPOINT then begin - if (PUint8(uint32(cfgBuf) + offset)^ >= sizeof(TUSBEndpointDescriptor)) and + if PUint8(PtrUInt(cfgBuf) + offset + 1)^ = USB_DESC_ENDPOINT then begin + if (PUint8(PtrUInt(cfgBuf) + offset)^ >= sizeof(TUSBEndpointDescriptor)) and (dev^.NumEndpoints < USB_MAX_ENDPOINTS) then begin - epDesc := PUSBEndpointDescriptor(uint32(cfgBuf) + offset); + epDesc := PUSBEndpointDescriptor(PtrUInt(cfgBuf) + offset); dev^.Endpoints[dev^.NumEndpoints].Address := usb_ep_number(epDesc^.bEndpointAddress); dev^.Endpoints[dev^.NumEndpoints].Direction := usb_ep_direction(epDesc^.bEndpointAddress); dev^.Endpoints[dev^.NumEndpoints].PipeType := usb_ep_pipe_type(epDesc^.bmAttributes); @@ -789,7 +800,7 @@ begin end; { Advance by bLength } - offset := offset + PUint8(uint32(cfgBuf) + offset)^; + offset := offset + PUint8(PtrUInt(cfgBuf) + offset)^; end; { Step 8: SET_CONFIGURATION } @@ -808,15 +819,15 @@ begin offset := sizeof(TUSBConfigDescriptor); ifDesc := nil; 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); + if PUint8(PtrUInt(cfgBuf) + offset)^ < 2 then break; + if offset + PUint8(PtrUInt(cfgBuf) + offset)^ > totalLen then break; + if (PUint8(PtrUInt(cfgBuf) + offset + 1)^ = USB_DESC_INTERFACE) and + (PUint8(PtrUInt(cfgBuf) + offset)^ >= sizeof(TUSBInterfaceDescriptor)) then begin + ifDesc := PUSBInterfaceDescriptor(PtrUInt(cfgBuf) + offset); dev^.InterfaceNumber := ifDesc^.bInterfaceNumber; break; end; - offset := offset + PUint8(uint32(cfgBuf) + offset)^; + offset := offset + PUint8(PtrUInt(cfgBuf) + offset)^; end; DevID := PDeviceIdentifier(kalloc(sizeof(TDeviceIdentifier))); @@ -837,15 +848,21 @@ begin end; DevID^.ex := nil; + deviceSlot := nil; + if hc^.Devices <> nil then deviceSlot := PPUSBDevice(LL_Add(hc^.Devices)); + if deviceSlot = nil then begin + kfree(void(DevID)); + kfree(void(cfgBuf)); + kfree(void(dev)); + pop_trace; + exit; + end; + deviceSlot^ := dev; driver.mgr.register_device('driver.bus.usb Device', DevID, void(dev)); kfree(void(DevID)); kfree(void(cfgBuf)); - { Track device in HC's device list (store pointer, not struct) } - if hc^.Devices <> nil then begin - puint32(LL_Add(hc^.Devices))^ := uint32(dev); - end; io.syslog.log('driver.bus.usb Core', 'Device enumerated at address '); io.syslog.writeintln(addr); @@ -915,13 +932,14 @@ begin { Remove from HC's device list } if (hc <> nil) and (hc^.Devices <> nil) then begin - for i := 0 to LL_Size(hc^.Devices) - 1 do begin - dptr := PUSBDevice(puint32(LL_Get(hc^.Devices, i))^); - if dptr = dev then begin - LL_Delete(hc^.Devices, i); - break; + if LL_Size(hc^.Devices) > 0 then + for i := 0 to LL_Size(hc^.Devices) - 1 do begin + dptr := PPUSBDevice(LL_Get(hc^.Devices, i))^; + if dptr = dev then begin + LL_Delete(hc^.Devices, i); + break; + end; end; - end; end; io.syslog.log('driver.bus.usb Core', 'Removed device at address '); @@ -961,13 +979,14 @@ begin { Check if a device is currently tracked on this port } found := false; if hc^.Devices <> nil then begin - for i := 0 to LL_Size(hc^.Devices) - 1 do begin - dev := PUSBDevice(puint32(LL_Get(hc^.Devices, i))^); - if (dev <> nil) and (dev^.HCPort = port) then begin - found := true; - break; + if LL_Size(hc^.Devices) > 0 then + for i := 0 to LL_Size(hc^.Devices) - 1 do begin + dev := PPUSBDevice(LL_Get(hc^.Devices, i))^; + if (dev <> nil) and (dev^.HCPort = port) then begin + found := true; + break; + end; end; - end; end; if (status AND $01) <> 0 then begin @@ -1002,6 +1021,7 @@ begin hc := PUSBHCDriver(LL_Get(HCList, i)); if (hc <> nil) and hc^.PortChangePending then begin hc^.PortChangePending := false; + if hc^.NumPorts > 0 then for port := 0 to hc^.NumPorts - 1 do usb_rescan_port(hc, port); end; @@ -1029,6 +1049,7 @@ begin io.stdio.bufWriteIntLn(stdout_buf, hcCount); io.stdio.bufWriteNewLine(stdout_buf); + if hcCount > 0 then for i := 0 to hcCount - 1 do begin hc := get_hc(i); if hc = nil then continue; @@ -1065,7 +1086,7 @@ begin io.stdio.bufWriteStrLn(stdout_buf, ' (no devices)'); end else begin for j := 0 to devCount - 1 do begin - dev := PUSBDevice(puint32(LL_Get(hc^.Devices, j))^); + dev := PPUSBDevice(LL_Get(hc^.Devices, j))^; if dev = nil then continue; io.stdio.bufWriteStr(stdout_buf, ' Dev '); @@ -1165,23 +1186,17 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('USBCORE', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('USBCORE', 'USBCORE_TESTS_PASSED', 'USBCORE_TESTS_FAILED', passed, failed); end; var + savedList: PLinkedListBase; + fixture, registered: PUSBHCDriver; + device: PUSBDevice; + slot: PPUSBDevice; + beforeFree: SizeUInt; + savedIRQ: PtrUInt; setup : TUSBSetupPacket; cfgBuf : Pointer; ifDesc : PUSBInterfaceDescriptor; @@ -1191,6 +1206,43 @@ begin failed := 0; io.syslog.logln('USBCORE', 'Unit tests starting...'); + savedIRQ := arch.platform.cpu.lock; + savedList := HCList; + beforeFree := lmm_total_free; + HCList := LL_New(sizeof(TUSBHCDriver)); + fixture := PUSBHCDriver(kalloc(sizeof(TUSBHCDriver))); + device := PUSBDevice(kalloc(sizeof(TUSBDevice))); + if (HCList <> nil) and (fixture <> nil) and (device <> nil) then begin + fixture^.Name := 'USB native-pointer fixture'; + registered := register_hc(fixture); + Assert(registered <> nil, 'register heap-backed controller'); + if registered <> nil then begin + Assert((registered <> fixture) and (get_hc(0) = registered), 'stable controller copy'); + slot := PPUSBDevice(LL_Add(registered^.Devices)); + Assert(slot <> nil, 'allocate native device slot'); + if slot <> nil then begin + slot^ := device; + device^.HC := registered; + Assert(PPUSBDevice(LL_Get(registered^.Devices, 0))^ = device, 'device slot preserves native pointer'); + usb_remove_device(device); + device := nil; + Assert(LL_Size(registered^.Devices) = 0, 'device removal detaches slot'); + end; + unregister_hc(registered); + Assert(get_hc_count = 0, 'controller removal releases registration'); + end; + unregister_hc(fixture); + poll_all; + usb_check_hotplug; + Assert(get_hc(0) = nil, 'empty controller list is safe'); + end else Assert(false, 'allocate controller fixture'); + if device <> nil then kfree(void(device)); + if fixture <> nil then kfree(void(fixture)); + if HCList <> nil then LL_Free(HCList); + HCList := savedList; + Assert(lmm_total_free = beforeFree, 'controller fixture releases owned memory'); + arch.platform.cpu.unlock(savedIRQ); + { === HC list management === } Assert(get_hc_count >= 0, 'hc_count non-negative'); @@ -1273,58 +1325,58 @@ begin Config(9) + Interface(9, class=$03, 2 EPs) + Endpoint(7, EP1 IN INT) + Endpoint(7, EP2 OUT BULK) + Interface(9, class=$08, 1 EP) + Endpoint(7, EP3 IN BULK) = 48 bytes total } cfgBuf := Pointer(kalloc(48)); - memset(uint32(cfgBuf), 0, 48); + memset(PtrUInt(cfgBuf), 0, 48); { Config descriptor header at offset 0 } - PUint8(uint32(cfgBuf) + 0)^ := 9; { bLength } - PUint8(uint32(cfgBuf) + 1)^ := USB_DESC_CONFIGURATION; { bDescriptorType } - PUint8(uint32(cfgBuf) + 2)^ := 48; { wTotalLength low } - PUint8(uint32(cfgBuf) + 3)^ := 0; { wTotalLength high } - PUint8(uint32(cfgBuf) + 4)^ := 2; { bNumInterfaces } - PUint8(uint32(cfgBuf) + 5)^ := 1; { bConfigurationValue } + PUint8(PtrUInt(cfgBuf) + 0)^ := 9; { bLength } + PUint8(PtrUInt(cfgBuf) + 1)^ := USB_DESC_CONFIGURATION; { bDescriptorType } + PUint8(PtrUInt(cfgBuf) + 2)^ := 48; { wTotalLength low } + PUint8(PtrUInt(cfgBuf) + 3)^ := 0; { wTotalLength high } + PUint8(PtrUInt(cfgBuf) + 4)^ := 2; { bNumInterfaces } + PUint8(PtrUInt(cfgBuf) + 5)^ := 1; { bConfigurationValue } { Interface 0 at offset 9: class=$03 (HID), 2 endpoints } - PUint8(uint32(cfgBuf) + 9)^ := 9; { bLength } - PUint8(uint32(cfgBuf) + 10)^ := USB_DESC_INTERFACE; - PUint8(uint32(cfgBuf) + 11)^ := 0; { bInterfaceNumber } - PUint8(uint32(cfgBuf) + 13)^ := 2; { bNumEndpoints } - PUint8(uint32(cfgBuf) + 14)^ := USB_CLASS_HID; { bInterfaceClass } - PUint8(uint32(cfgBuf) + 15)^ := $01; { bInterfaceSubClass (boot) } - PUint8(uint32(cfgBuf) + 16)^ := $01; { bInterfaceProtocol (driver.hid.keyboard) } + PUint8(PtrUInt(cfgBuf) + 9)^ := 9; { bLength } + PUint8(PtrUInt(cfgBuf) + 10)^ := USB_DESC_INTERFACE; + PUint8(PtrUInt(cfgBuf) + 11)^ := 0; { bInterfaceNumber } + PUint8(PtrUInt(cfgBuf) + 13)^ := 2; { bNumEndpoints } + PUint8(PtrUInt(cfgBuf) + 14)^ := USB_CLASS_HID; { bInterfaceClass } + PUint8(PtrUInt(cfgBuf) + 15)^ := $01; { bInterfaceSubClass (boot) } + PUint8(PtrUInt(cfgBuf) + 16)^ := $01; { bInterfaceProtocol (driver.hid.keyboard) } { Endpoint at offset 18: EP1 IN Interrupt, maxpacket=8, interval=10 } - PUint8(uint32(cfgBuf) + 18)^ := 7; { bLength } - PUint8(uint32(cfgBuf) + 19)^ := USB_DESC_ENDPOINT; - PUint8(uint32(cfgBuf) + 20)^ := $81; { bEndpointAddress: EP1 IN } - PUint8(uint32(cfgBuf) + 21)^ := USB_EP_ATTR_INTERRUPT; { bmAttributes } - PUint8(uint32(cfgBuf) + 22)^ := 8; { wMaxPacketSize low } - PUint8(uint32(cfgBuf) + 23)^ := 0; { wMaxPacketSize high } - PUint8(uint32(cfgBuf) + 24)^ := 10; { bInterval } + PUint8(PtrUInt(cfgBuf) + 18)^ := 7; { bLength } + PUint8(PtrUInt(cfgBuf) + 19)^ := USB_DESC_ENDPOINT; + PUint8(PtrUInt(cfgBuf) + 20)^ := $81; { bEndpointAddress: EP1 IN } + PUint8(PtrUInt(cfgBuf) + 21)^ := USB_EP_ATTR_INTERRUPT; { bmAttributes } + PUint8(PtrUInt(cfgBuf) + 22)^ := 8; { wMaxPacketSize low } + PUint8(PtrUInt(cfgBuf) + 23)^ := 0; { wMaxPacketSize high } + PUint8(PtrUInt(cfgBuf) + 24)^ := 10; { bInterval } { Endpoint at offset 25: EP2 OUT Bulk, maxpacket=64 } - PUint8(uint32(cfgBuf) + 25)^ := 7; { bLength } - PUint8(uint32(cfgBuf) + 26)^ := USB_DESC_ENDPOINT; - PUint8(uint32(cfgBuf) + 27)^ := $02; { bEndpointAddress: EP2 OUT } - PUint8(uint32(cfgBuf) + 28)^ := USB_EP_ATTR_BULK; { bmAttributes } - PUint8(uint32(cfgBuf) + 29)^ := 64; { wMaxPacketSize low } - PUint8(uint32(cfgBuf) + 30)^ := 0; { wMaxPacketSize high } - PUint8(uint32(cfgBuf) + 31)^ := 0; { bInterval } + PUint8(PtrUInt(cfgBuf) + 25)^ := 7; { bLength } + PUint8(PtrUInt(cfgBuf) + 26)^ := USB_DESC_ENDPOINT; + PUint8(PtrUInt(cfgBuf) + 27)^ := $02; { bEndpointAddress: EP2 OUT } + PUint8(PtrUInt(cfgBuf) + 28)^ := USB_EP_ATTR_BULK; { bmAttributes } + PUint8(PtrUInt(cfgBuf) + 29)^ := 64; { wMaxPacketSize low } + PUint8(PtrUInt(cfgBuf) + 30)^ := 0; { wMaxPacketSize high } + PUint8(PtrUInt(cfgBuf) + 31)^ := 0; { bInterval } { Interface 1 at offset 32: class=$08 (mass storage), 1 endpoint } - PUint8(uint32(cfgBuf) + 32)^ := 9; { bLength } - PUint8(uint32(cfgBuf) + 33)^ := USB_DESC_INTERFACE; - PUint8(uint32(cfgBuf) + 34)^ := 1; { bInterfaceNumber } - PUint8(uint32(cfgBuf) + 36)^ := 1; { bNumEndpoints } - PUint8(uint32(cfgBuf) + 37)^ := USB_CLASS_MASS_STORAGE; { bInterfaceClass } + PUint8(PtrUInt(cfgBuf) + 32)^ := 9; { bLength } + PUint8(PtrUInt(cfgBuf) + 33)^ := USB_DESC_INTERFACE; + PUint8(PtrUInt(cfgBuf) + 34)^ := 1; { bInterfaceNumber } + PUint8(PtrUInt(cfgBuf) + 36)^ := 1; { bNumEndpoints } + PUint8(PtrUInt(cfgBuf) + 37)^ := USB_CLASS_MASS_STORAGE; { bInterfaceClass } { Endpoint at offset 41: EP3 IN Bulk, maxpacket=512 } - PUint8(uint32(cfgBuf) + 41)^ := 7; { bLength } - PUint8(uint32(cfgBuf) + 42)^ := USB_DESC_ENDPOINT; - PUint8(uint32(cfgBuf) + 43)^ := $83; { bEndpointAddress: EP3 IN } - PUint8(uint32(cfgBuf) + 44)^ := USB_EP_ATTR_BULK; { bmAttributes } - PUint8(uint32(cfgBuf) + 45)^ := 0; { wMaxPacketSize low = 512 = $0200 } - PUint8(uint32(cfgBuf) + 46)^ := 2; { wMaxPacketSize high } - PUint8(uint32(cfgBuf) + 47)^ := 0; { bInterval } + PUint8(PtrUInt(cfgBuf) + 41)^ := 7; { bLength } + PUint8(PtrUInt(cfgBuf) + 42)^ := USB_DESC_ENDPOINT; + PUint8(PtrUInt(cfgBuf) + 43)^ := $83; { bEndpointAddress: EP3 IN } + PUint8(PtrUInt(cfgBuf) + 44)^ := USB_EP_ATTR_BULK; { bmAttributes } + PUint8(PtrUInt(cfgBuf) + 45)^ := 0; { wMaxPacketSize low = 512 = $0200 } + PUint8(PtrUInt(cfgBuf) + 46)^ := 2; { wMaxPacketSize high } + PUint8(PtrUInt(cfgBuf) + 47)^ := 0; { bInterval } { --- usb_find_interface (first interface) --- } ifDesc := usb_find_interface(cfgBuf, 48); diff --git a/src/driver/bus/usb/driver.bus.usb.hub.pas b/src/driver/bus/usb/driver.bus.usb.hub.pas index 6a48ffff..ba8866e3 100644 --- a/src/driver/bus/usb/driver.bus.usb.hub.pas +++ b/src/driver/bus/usb/driver.bus.usb.hub.pas @@ -15,7 +15,7 @@ interface uses debug.tracer, io.syslog, - core.util, arch.x86.util, + core.util, arch.platform.cpu, arch.platform.diagnostics, memory.heap, driver.types, driver.mgr, @@ -315,7 +315,7 @@ begin io.syslog.writeintln(depth); { Step 1: Get hub descriptor } - memset(uint32(@hubDesc), 0, sizeof(TUSBHubDescriptor)); + memset(PtrUInt(@hubDesc), 0, sizeof(TUSBHubDescriptor)); if not hub_get_descriptor(dev, @hubDesc, sizeof(TUSBHubDescriptor)) then begin io.syslog.logln('USBHub', 'Failed to get hub descriptor.'); pop_trace; @@ -344,7 +344,7 @@ begin pop_trace; exit; end; - memset(uint32(hub), 0, sizeof(TUSBHubData)); + memset(PtrUInt(hub), 0, sizeof(TUSBHubData)); hub^.Device := dev; hub^.NumPorts := hubDesc.bNbrPorts; hub^.PwrOn2PwrGood := hubDesc.bPwrOn2PwrGood; @@ -378,7 +378,7 @@ begin if HubList <> nil then begin hubEntry := PUSBHubData(LL_Add(HubList)); if hubEntry <> nil then - memcpy(uint32(hub), uint32(hubEntry), sizeof(TUSBHubData)); + memcpy(PtrUInt(hub), PtrUInt(hubEntry), sizeof(TUSBHubData)); end; { Step 6: Scan ports for connected devices } @@ -649,20 +649,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('USBHub', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('USBHub', 'USBHUB_TESTS_PASSED', 'USBHUB_TESTS_FAILED', passed, failed); end; begin diff --git a/src/driver/bus/usb/driver.bus.usb.ohci.pas b/src/driver/bus/usb/driver.bus.usb.ohci.pas index 528d2623..acebdecf 100644 --- a/src/driver/bus/usb/driver.bus.usb.ohci.pas +++ b/src/driver/bus/usb/driver.bus.usb.ohci.pas @@ -31,14 +31,13 @@ uses io.syslog, driver.bus.pci, driver.types, - arch.x86.memory.physical, - arch.x86.memory.virtual, + arch.platform.memory, memory.heap, - core.util, arch.x86.util, + core.util, arch.platform.cpu, arch.platform.diagnostics, driver.mgr, driver.bus.usb.types, driver.bus.usb.core, - arch.x86.isr.mgr, + arch.platform.interrupts, core.ds.lists, core.strings; @@ -223,8 +222,8 @@ type { Software fields - beyond the 16 bytes the HC reads } SWNext : POHCI_ED; { Software linked list for traversal } SWTransfer : Pointer; { Back-pointer to owning TUSBTransfer } - SWPad1 : uint32; - SWPad2 : uint32; + SWPad1 : PtrUInt; + SWPad2 : PtrUInt; end; { General Transfer Descriptor (TD) - 16 bytes, 16-byte aligned } @@ -244,7 +243,7 @@ type { Private data for an driver.bus.usb.ohci host controller instance } POHCI_PrivData = ^TOHCI_PrivData; TOHCI_PrivData = record - MMIOBase : uint32; { MMIO base address (virtual = physical, identity mapped) } + MMIOBase : PtrUInt; { MMIO base address (virtual = physical, identity mapped) } HCCA : POHCI_HCCA; { 256-byte aligned HCCA } EDControl : POHCI_ED; { Head of control ED list } EDBulk : POHCI_ED; { Head of bulk ED list } @@ -258,24 +257,49 @@ type { ========================= MMIO Helpers ========================= } -procedure ohci_write(base : uint32; reg : uint32; val : uint32); +procedure ohci_write(base : PtrUInt; reg : uint32; val : uint32); begin PUint32(base + reg)^ := val; end; -function ohci_read(base : uint32; reg : uint32) : uint32; +function ohci_read(base : PtrUInt; reg : uint32) : uint32; begin ohci_read := PUint32(base + reg)^; end; +{ OHCI exposes only 32-bit DMA addresses. Validate every backing page before + publishing descriptors; a high virtual address is valid when its backing RAM + is below 4 GiB. Zero-length transfers do not need a buffer. } +function ohci_dma_addressable(address: PtrUInt; bytes: uint32): boolean; +var + physical: uint64; + chunk: uint32; +begin + ohci_dma_addressable := false; + if bytes > High(PtrUInt) - address then exit; + while bytes > 0 do begin + physical := arch.platform.memory.physicalAddress(address); + if (physical = 0) or (physical > $FFFFFFFF) then exit; + chunk := 4096 - (address and 4095); + if chunk > bytes then chunk := bytes; + inc(address, chunk); + dec(bytes, chunk); + end; + ohci_dma_addressable := true; +end; + { ========================= ED/TD Construction Helpers ========================= } { Allocate an ED (16-byte aligned) } function ohci_alloc_ed : POHCI_ED; begin ohci_alloc_ed := POHCI_ED(kalloc_aligned(sizeof(TOHCI_ED), OHCI_ED_ALIGN)); - if ohci_alloc_ed <> nil then - memset(uint32(ohci_alloc_ed), 0, sizeof(TOHCI_ED)); + if ohci_alloc_ed <> nil then begin + if not ohci_dma_addressable(PtrUInt(ohci_alloc_ed), 16) then begin + kfree_aligned(ohci_alloc_ed); + ohci_alloc_ed := nil; + end; + end; end; { Free an ED } @@ -289,8 +313,12 @@ end; function ohci_alloc_td : POHCI_TD; begin ohci_alloc_td := POHCI_TD(kalloc_aligned(sizeof(TOHCI_TD), OHCI_TD_ALIGN)); - if ohci_alloc_td <> nil then - memset(uint32(ohci_alloc_td), 0, sizeof(TOHCI_TD)); + if ohci_alloc_td <> nil then begin + if not ohci_dma_addressable(PtrUInt(ohci_alloc_td), 16) then begin + kfree_aligned(ohci_alloc_td); + ohci_alloc_td := nil; + end; + end; end; { Free a TD } @@ -379,7 +407,7 @@ function ohci_port_status(hc : PUSBHCDriver; port : uint8) : uint32; forward; function ohci_reset(hc : PUSBHCDriver) : boolean; var priv : POHCI_PrivData; - base : uint32; + base : PtrUInt; loops : uint32; fmival : uint32; begin @@ -458,7 +486,11 @@ begin pop_trace; exit; end; - memset(uint32(hcca), 0, OHCI_HCCA_SIZE); + if not ohci_dma_addressable(PtrUInt(hcca), OHCI_HCCA_SIZE) then begin + kfree_aligned(hcca); + pop_trace; + exit; + end; priv^.HCCA := hcca; { Allocate dummy/sentinel EDs for each list head } @@ -494,14 +526,14 @@ begin { Fill all 32 HCCA interrupt table entries with our interrupt sentinel ED (physical) } for i := 0 to OHCI_HCCA_INTR_TABLE_SIZE - 1 do - hcca^.HccaInterruptTable[i] := vtop(uint32(priv^.EDInterrupt)); + hcca^.HccaInterruptTable[i] := arch.platform.memory.physicalAddress(PtrUInt(priv^.EDInterrupt)); { Set HC's HCCA pointer (physical) } - ohci_write(priv^.MMIOBase, OHCI_REG_HCCA, vtop(uint32(hcca))); + ohci_write(priv^.MMIOBase, OHCI_REG_HCCA, arch.platform.memory.physicalAddress(PtrUInt(hcca))); { Set control and bulk list heads (physical) } - ohci_write(priv^.MMIOBase, OHCI_REG_CONTROL_HEAD_ED, vtop(uint32(priv^.EDControl))); - ohci_write(priv^.MMIOBase, OHCI_REG_BULK_HEAD_ED, vtop(uint32(priv^.EDBulk))); + ohci_write(priv^.MMIOBase, OHCI_REG_CONTROL_HEAD_ED, arch.platform.memory.physicalAddress(PtrUInt(priv^.EDControl))); + ohci_write(priv^.MMIOBase, OHCI_REG_BULK_HEAD_ED, arch.platform.memory.physicalAddress(PtrUInt(priv^.EDBulk))); io.syslog.logln('driver.bus.usb.ohci', 'Schedule configured.'); pop_trace; @@ -512,7 +544,7 @@ end; function ohci_start(hc : PUSBHCDriver) : boolean; var priv : POHCI_PrivData; - base : uint32; + base : PtrUInt; ctrl : uint32; rha : uint32; loops : uint32; @@ -527,6 +559,12 @@ begin priv := POHCI_PrivData(hc^.PrivData); base := priv^.MMIOBase; + if (priv^.HCCA = nil) or (priv^.EDControl = nil) or + (priv^.EDBulk = nil) or (priv^.EDInterrupt = nil) then begin + pop_trace; + exit; + end; + { Transition to USBOperational, enable control + bulk core.ds.lists } ctrl := OHCI_CTRL_HCFS_OPERATIONAL OR OHCI_CTRL_CLE @@ -620,7 +658,7 @@ end; function ohci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; var priv : POHCI_PrivData; - base : uint32; + base : PtrUInt; regOfs : uint32; status : uint32; loops : uint32; @@ -688,7 +726,7 @@ begin if (sentinel = nil) or (ed = nil) then exit; ed^.NextED := sentinel^.NextED; ed^.SWNext := sentinel^.SWNext; - sentinel^.NextED := vtop(uint32(ed)); + sentinel^.NextED := arch.platform.memory.physicalAddress(PtrUInt(ed)); sentinel^.SWNext := ed; end; @@ -735,8 +773,8 @@ begin td^.Control := ohci_make_td_control(OHCI_TD_DP_SETUP, OHCI_TD_DT_DATA0, OHCI_TD_DI_NONE, false); - td^.CBP := vtop(uint32(@transfer^.Setup)); - td^.BE := vtop(uint32(@transfer^.Setup) + 7); + td^.CBP := arch.platform.memory.physicalAddress(PtrUInt(@transfer^.Setup)); + td^.BE := arch.platform.memory.physicalAddress(PtrUInt(@transfer^.Setup) + 7); td^.NextTD := 0; td^.SWTransfer := Pointer(transfer); td^.SWNext := nil; @@ -764,9 +802,9 @@ begin td^.Control := ohci_make_td_control(dirPID, toggle, OHCI_TD_DI_NONE, true); - td^.CBP := vtop(uint32(transfer^.Buffer) + offset); + td^.CBP := arch.platform.memory.physicalAddress(PtrUInt(transfer^.Buffer) + offset); if pktLen > 0 then - td^.BE := vtop(uint32(transfer^.Buffer) + offset + uint32(pktLen) - 1) + td^.BE := arch.platform.memory.physicalAddress(PtrUInt(transfer^.Buffer) + offset + uint32(pktLen) - 1) else td^.BE := 0; td^.SWPad := pktLen; { Original data length, excluding SETUP/status } @@ -775,7 +813,7 @@ begin td^.SWNext := nil; { Link previous TD (NextTD = physical) } - prevTD^.NextTD := vtop(uint32(td)); + prevTD^.NextTD := arch.platform.memory.physicalAddress(PtrUInt(td)); prevTD^.SWNext := td; prevTD := td; @@ -807,13 +845,13 @@ begin td^.SWTransfer := Pointer(transfer); td^.SWNext := nil; - prevTD^.NextTD := vtop(uint32(td)); + prevTD^.NextTD := arch.platform.memory.physicalAddress(PtrUInt(td)); prevTD^.SWNext := td; { Allocate a dummy/sentinel TD for the tail pointer (driver.bus.usb.ohci requires HeadP <> TailP to process) } tailTD := ohci_alloc_td; if tailTD = nil then begin ohci_free_td_chain(firstTD); pop_trace; exit; end; - td^.NextTD := vtop(uint32(tailTD)); + td^.NextTD := arch.platform.memory.physicalAddress(PtrUInt(tailTD)); td^.SWNext := tailTD; { === Create ED === } @@ -822,12 +860,12 @@ begin ed^.Control := ohci_make_ed_control(devAddr, 0, OHCI_ED_DIR_FROM_TD, speedBit, maxPkt, false); - ed^.HeadP := vtop(uint32(firstTD)); { First real TD (physical) } - ed^.TailP := vtop(uint32(tailTD)); { Sentinel past last TD (physical) } + ed^.HeadP := arch.platform.memory.physicalAddress(PtrUInt(firstTD)); { First real TD (physical) } + ed^.TailP := arch.platform.memory.physicalAddress(PtrUInt(tailTD)); { Sentinel past last TD (physical) } ed^.NextED := 0; ed^.SWTransfer := Pointer(transfer); - ed^.SWPad1 := uint32(firstTD); { Virtual firstTD for cleanup } - ed^.SWPad2 := uint32(tailTD); { Virtual tailTD for cleanup } + ed^.SWPad1 := PtrUInt(firstTD); { Virtual firstTD for cleanup } + ed^.SWPad2 := PtrUInt(tailTD); { Virtual tailTD for cleanup } { Store ED in transfer for cleanup and poll } transfer^.HCPriv := Pointer(ed); @@ -924,8 +962,8 @@ begin td^.Control := ohci_make_td_control(dirPID, toggle, OHCI_TD_DI_NONE, transfer^.PipeType <> ptBulk); if pktLen > 0 then begin - td^.CBP := vtop(uint32(transfer^.Buffer) + offset); - td^.BE := vtop(uint32(transfer^.Buffer) + offset + uint32(pktLen) - 1) + td^.CBP := arch.platform.memory.physicalAddress(PtrUInt(transfer^.Buffer) + offset); + td^.BE := arch.platform.memory.physicalAddress(PtrUInt(transfer^.Buffer) + offset + uint32(pktLen) - 1) end else begin td^.CBP := 0; td^.BE := 0; @@ -936,7 +974,7 @@ begin td^.SWNext := nil; if prevTD <> nil then begin - prevTD^.NextTD := vtop(uint32(td)); + prevTD^.NextTD := arch.platform.memory.physicalAddress(PtrUInt(td)); prevTD^.SWNext := td; end; prevTD := td; @@ -966,7 +1004,7 @@ begin { Allocate tail sentinel TD } tailTD := ohci_alloc_td; if tailTD = nil then begin ohci_free_td_chain(firstTD); pop_trace; exit; end; - prevTD^.NextTD := vtop(uint32(tailTD)); + prevTD^.NextTD := arch.platform.memory.physicalAddress(PtrUInt(tailTD)); prevTD^.SWNext := tailTD; { Create ED } @@ -975,14 +1013,14 @@ begin ed^.Control := ohci_make_ed_control(devAddr, epNum, edDir, speedBit, maxPkt, false); - ed^.HeadP := vtop(uint32(firstTD)); + ed^.HeadP := arch.platform.memory.physicalAddress(PtrUInt(firstTD)); if transfer^.PipeType = ptBulk then ed^.HeadP := ed^.HeadP or ((uint32(transfer^.Endpoint^.Toggle) and 1) shl 1); - ed^.TailP := vtop(uint32(tailTD)); + ed^.TailP := arch.platform.memory.physicalAddress(PtrUInt(tailTD)); ed^.NextED := 0; ed^.SWTransfer := Pointer(transfer); - ed^.SWPad1 := uint32(firstTD); { Virtual firstTD for cleanup } - ed^.SWPad2 := uint32(tailTD); { Virtual tailTD for cleanup } + ed^.SWPad1 := PtrUInt(firstTD); { Virtual firstTD for cleanup } + ed^.SWPad2 := PtrUInt(tailTD); { Virtual tailTD for cleanup } transfer^.HCPriv := Pointer(ed); transfer^.Status := tsInProgress; @@ -1009,6 +1047,12 @@ begin exit; end; + if not ohci_dma_addressable(PtrUInt(transfer^.Buffer), transfer^.BufferLen) or + not ohci_dma_addressable(PtrUInt(@transfer^.Setup), sizeof(TUSBSetupPacket)) then begin + pop_trace; + exit; + end; + case transfer^.PipeType of ptControl: ohci_submit := ohci_submit_control(hc, transfer); @@ -1071,6 +1115,7 @@ var priv : POHCI_PrivData; intSts : uint32; begin + if OHCIInstanceCount = 0 then exit; for i := 0 to OHCIInstanceCount - 1 do begin hc := OHCIInstances[i]; if hc = nil then continue; @@ -1127,7 +1172,7 @@ end; procedure ohci_poll(hc : PUSBHCDriver); var priv : POHCI_PrivData; - base : uint32; + base : PtrUInt; intSts : uint32; sentinel : POHCI_ED; ed : POHCI_ED; @@ -1236,8 +1281,7 @@ var priv : POHCI_PrivData; hc : TUSBHCDriver; hcEntry : PUSBHCDriver; - mmioBase : uint32; - block : uint32; + mmioBase : PtrUInt; begin push_trace('driver.bus.usb.ohci.load'); load := false; @@ -1272,9 +1316,8 @@ begin end; { Identity-map the MMIO region so we can access it } - block := mmioBase SHR 22; - force_alloc_block(block, 0); - map_page(block, block); + mmioBase := PtrUInt(arch.platform.memory.mapDevice(mmioBase, 4096)); + if mmioBase = 0 then continue; { Enable driver.bus.pci bus mastering } driver.bus.pci.setBusMaster(devices[i].bus, devices[i].slot, devices[i].func, true); @@ -1285,7 +1328,7 @@ begin io.syslog.logln('driver.bus.usb.ohci', 'Failed to allocate private data!'); continue; end; - memset(uint32(priv), 0, sizeof(TOHCI_PrivData)); + memset(PtrUInt(priv), 0, sizeof(TOHCI_PrivData)); priv^.MMIOBase := mmioBase; priv^.PCIBus := devices[i].bus; priv^.PCISlot := devices[i].slot; @@ -1348,7 +1391,8 @@ begin { Register ISR on driver.bus.pci interrupt line } io.syslog.log('driver.bus.usb.ohci', 'Registering ISR on IRQ '); io.syslog.writeintln(devices[i].interrupt_line); - arch.x86.isr.mgr.registerISR(32 + devices[i].interrupt_line, @ohci_isr); + arch.platform.interrupts.registerIRQ(32 + devices[i].interrupt_line, @ohci_isr); + arch.platform.interrupts.routePCI(devices[i].interrupt_line, 32 + devices[i].interrupt_line); { Enable hardware interrupts } ohci_enable_interrupts(hcEntry); @@ -1386,20 +1430,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('driver.bus.usb.ohci', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('OHCI', 'OHCI_TESTS_PASSED', 'OHCI_TESTS_FAILED', passed, failed); end; var @@ -1414,9 +1446,12 @@ begin io.syslog.logln('driver.bus.usb.ohci', 'Unit tests starting...'); { === Structure Sizes === } + Assert(ohci_dma_addressable(0, 0), 'empty transfer requires no DMA buffer'); + Assert(not ohci_dma_addressable(0, 16), 'unmapped DMA buffer rejected'); + Assert(not ohci_dma_addressable(High(PtrUInt) - 7, 16), 'DMA address wrap rejected'); Assert(sizeof(TOHCI_HCCA) = 256, 'sizeof HCCA=256'); - Assert(sizeof(TOHCI_ED) = 32, 'sizeof ED=32'); - Assert(sizeof(TOHCI_TD) = 32, 'sizeof TD=32'); + Assert(PtrUInt(@POHCI_ED(nil)^.SWNext) = 16, 'ED hardware prefix remains 16 bytes'); + Assert(PtrUInt(@POHCI_TD(nil)^.SWNext) = 16, 'TD hardware prefix remains 16 bytes'); { === ED Control Building === } { Addr 0, EP0, direction from TD, full speed, maxPkt 8, general } @@ -1487,7 +1522,11 @@ begin { === ED Allocation & Alignment === } ed := ohci_alloc_ed; Assert(ed <> nil, 'alloc_ed not nil'); - Assert((uint32(ed) AND $0F) = 0, 'alloc_ed 16-byte aligned'); + Assert((PtrUInt(ed) AND $0F) = 0, 'alloc_ed 16-byte aligned'); + if ed <> nil then begin + ed^.SWPad1 := PtrUInt(ed); + Assert(POHCI_ED(ed^.SWPad1) = ed, 'ED software pointer retains native width'); + end; Assert(ed^.Control = 0, 'alloc_ed zeroed control'); Assert(ed^.TailP = 0, 'alloc_ed zeroed tailp'); Assert(ed^.HeadP = 0, 'alloc_ed zeroed headp'); @@ -1497,7 +1536,7 @@ begin { === TD Allocation & Alignment === } td := ohci_alloc_td; Assert(td <> nil, 'alloc_td not nil'); - Assert((uint32(td) AND $0F) = 0, 'alloc_td 16-byte aligned'); + Assert((PtrUInt(td) AND $0F) = 0, 'alloc_td 16-byte aligned'); Assert(td^.Control = 0, 'alloc_td zeroed control'); Assert(td^.CBP = 0, 'alloc_td zeroed cbp'); Assert(td^.NextTD = 0, 'alloc_td zeroed nexttd'); @@ -1519,7 +1558,7 @@ begin Assert(OHCI_HCCA_ALIGN = 256, 'HCCA_ALIGN=256'); hcca := POHCI_HCCA(kalloc_aligned(OHCI_HCCA_SIZE, OHCI_HCCA_ALIGN)); Assert(hcca <> nil, 'hcca alloc not nil'); - Assert((uint32(hcca) AND $FF) = 0, 'hcca 256-byte aligned'); + Assert((PtrUInt(hcca) AND $FF) = 0, 'hcca 256-byte aligned'); kfree_aligned(hcca); { === Register offset constants === } diff --git a/src/driver/bus/usb/driver.bus.usb.types.pas b/src/driver/bus/usb/driver.bus.usb.types.pas index cc54b8e2..002b7b6d 100644 --- a/src/driver/bus/usb/driver.bus.usb.types.pas +++ b/src/driver/bus/usb/driver.bus.usb.types.pas @@ -23,7 +23,7 @@ unit driver.bus.usb.types; interface uses - core.util, arch.x86.util, + core.util, arch.platform.cpu, arch.platform.diagnostics, memory.heap, driver.types, core.ds.lists, @@ -229,6 +229,7 @@ type { ---- Forward Declarations ---- } PUSBDevice = ^TUSBDevice; + PPUSBDevice = ^PUSBDevice; PUSBHCDriver = ^TUSBHCDriver; PUSBTransfer = ^TUSBTransfer; @@ -286,7 +287,7 @@ type HCType : uint8; { USB_HC_UHCI / driver.bus.usb.ohci / driver.bus.usb.ehci / driver.bus.usb.xhci } NumPorts : uint8; PCIDev : TPCI_Device; { Owning driver.bus.pci device } - BaseAddr : uint32; { I/O base (driver.bus.usb.uhci) or MMIO base (driver.bus.usb.ohci/driver.bus.usb.ehci/driver.bus.usb.xhci) } + BaseAddr : PtrUInt; { I/O base (driver.bus.usb.uhci) or MMIO base (driver.bus.usb.ohci/driver.bus.usb.ehci/driver.bus.usb.xhci) } PrivData : Pointer; { HC-specific state } Devices : PLinkedListBase; { List of PUSBDevice attached } NextAddress : uint8; { Next available driver.bus.usb address (1-127) } @@ -341,37 +342,31 @@ implementation { ========================= Alignment Helpers ========================= } function kalloc_aligned(size : uint32; alignment : uint32) : Pointer; +type + PAllocation = ^PtrUInt; var - raw : uint32; - aligned : uint32; - overhead : uint32; + raw, aligned, overhead: PtrUInt; begin - push_trace('driver.bus.usb.types.kalloc_aligned'); - if alignment < 4 then alignment := 4; - overhead := alignment + sizeof(uint32); - raw := uint32(kalloc(size + overhead)); - if raw = 0 then begin - kalloc_aligned := nil; - pop_trace; - exit; - end; - aligned := (raw + sizeof(uint32) + alignment - 1) AND (NOT (alignment - 1)); - { Store original raw pointer just before the aligned address } - PUint32(aligned - 4)^ := raw; - kalloc_aligned := Pointer(aligned); - pop_trace; + kalloc_aligned := nil; + if (size = 0) or (alignment = 0) or + ((alignment and (alignment - 1)) <> 0) then exit; + if alignment < sizeof(PtrUInt) then alignment := sizeof(PtrUInt); + overhead := PtrUInt(alignment) - 1 + sizeof(PtrUInt); + if PtrUInt(size) > High(PtrUInt) - overhead then exit; + raw := PtrUInt(kalloc(PtrUInt(size) + overhead)); + if raw = 0 then exit; + aligned := (raw + sizeof(PtrUInt) + alignment - 1) and + not (PtrUInt(alignment) - 1); + PAllocation(aligned - sizeof(PtrUInt))^ := raw; + kalloc_aligned := pointer(aligned); end; procedure kfree_aligned(p : Pointer); -var - raw : uint32; +type + PAllocation = ^PtrUInt; begin - push_trace('driver.bus.usb.types.kfree_aligned'); - if p <> nil then begin - raw := PUint32(uint32(p) - 4)^; - kfree(void(raw)); - end; - pop_trace; + if p <> nil then + kfree(void(PAllocation(PtrUInt(p) - sizeof(PtrUInt))^)); end; { ========================= Setup Packet Builder ========================= } @@ -457,6 +452,7 @@ var passed, failed : uint32; p : Pointer; setup : TUSBSetupPacket; + beforeFree: SizeUInt; procedure Assert(condition : boolean; testName : pchar); var @@ -473,20 +469,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('USBTYPES', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('USBTYPES', 'USBTYPES_TESTS_PASSED', 'USBTYPES_TESTS_FAILED', passed, failed); end; begin @@ -502,35 +486,41 @@ begin Assert(sizeof(TUSBSetupPacket) = 8, 'sizeof SetupPacket=8'); Assert(sizeof(TUSBHubDescriptor) = 7, 'sizeof HubDescriptor=7'); + beforeFree := lmm_total_free; + Assert(kalloc_aligned(0, 16) = nil, 'zero allocation rejected'); + Assert(kalloc_aligned(16, 0) = nil, 'zero alignment rejected'); + Assert(kalloc_aligned(16, 24) = nil, 'non-power-of-two alignment rejected'); { === kalloc_aligned / kfree_aligned === } { 16-byte alignment } p := kalloc_aligned(32, 16); Assert(p <> nil, 'kalloc_aligned(32,16) not nil'); - Assert((uint32(p) AND $0F) = 0, 'kalloc_aligned(32,16) aligned to 16'); + Assert((PtrUInt(p) AND $0F) = 0, 'kalloc_aligned(32,16) aligned to 16'); kfree_aligned(p); { 256-byte alignment (HCCA) } p := kalloc_aligned(256, 256); Assert(p <> nil, 'kalloc_aligned(256,256) not nil'); - Assert((uint32(p) AND $FF) = 0, 'kalloc_aligned(256,256) aligned to 256'); + Assert((PtrUInt(p) AND $FF) = 0, 'kalloc_aligned(256,256) aligned to 256'); kfree_aligned(p); { 4096-byte alignment (frame list) } p := kalloc_aligned(4096, 4096); Assert(p <> nil, 'kalloc_aligned(4096,4096) not nil'); - Assert((uint32(p) AND $FFF) = 0, 'kalloc_aligned(4096,4096) aligned to 4096'); + Assert((PtrUInt(p) AND $FFF) = 0, 'kalloc_aligned(4096,4096) aligned to 4096'); kfree_aligned(p); { 32-byte alignment (qTD) } p := kalloc_aligned(32, 32); Assert(p <> nil, 'kalloc_aligned(32,32) not nil'); - Assert((uint32(p) AND $1F) = 0, 'kalloc_aligned(32,32) aligned to 32'); + Assert((PtrUInt(p) AND $1F) = 0, 'kalloc_aligned(32,32) aligned to 32'); kfree_aligned(p); { kfree_aligned(nil) should not crash } kfree_aligned(nil); Assert(true, 'kfree_aligned(nil) no crash'); + Assert(lmm_total_free = beforeFree, 'aligned allocations release native base pointers'); + { === make_setup_packet === } setup := make_setup_packet($80, USB_REQ_GET_DESCRIPTOR, $0100, $0000, 18); Assert(setup.bmRequestType = $80, 'setup bmRequestType=$80'); diff --git a/src/driver/hid/usb/driver.hid.usb.keyboard.pas b/src/driver/hid/usb/driver.hid.usb.keyboard.pas index ac7dffdc..de25aee6 100644 --- a/src/driver/hid/usb/driver.hid.usb.keyboard.pas +++ b/src/driver/hid/usb/driver.hid.usb.keyboard.pas @@ -12,18 +12,19 @@ unit driver.hid.usb.keyboard; interface uses - boot.mgr, driver.bus.usb.types, driver.bus.usb.core, driver.hid.keyboard, - driver.hid.ps2.keyboard, driver.mgr, memory.heap, core.ds.lists, debug.tracer, io.syslog, core.strings, - core.util, arch.x86.util; + core.util, arch.platform.cpu, arch.platform.diagnostics; + +{ Target startup may disable a legacy keyboard when USB becomes active. } +var onAttach: procedure = nil; procedure init; procedure poll_keyboards; @@ -400,7 +401,7 @@ begin end; { Save current report as previous for next comparison } - memcpy(uint32(@kb^.ReportBuf[0]), uint32(@kb^.PrevReport[0]), KB_REPORT_SIZE); + memcpy(PtrUInt(@kb^.ReportBuf[0]), PtrUInt(@kb^.PrevReport[0]), KB_REPORT_SIZE); end; { ========================= Disconnect Handler ========================= } @@ -573,7 +574,7 @@ begin io.syslog.writestringln(').'); { Disable PS/2 driver.hid.keyboard to prevent duplicate input from driver.bus.usb legacy emulation } - driver.hid.ps2.keyboard.disable; + if onAttach <> nil then onAttach; load := true; pop_trace; @@ -632,20 +633,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('USBKeyboard', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('USBKeyboard', 'USBKEYBOARD_TESTS_PASSED', 'USBKEYBOARD_TESTS_FAILED', passed, failed); end; var @@ -754,7 +743,4 @@ begin PrintSummary; end; -initialization - boot.mgr.registerBoot('driver.hid.usb.keyboard', @init, 'USB Keyboard Driver', BOOT_MGR_BARRIER_DEVICE); - end. diff --git a/src/driver/hid/usb/driver.hid.usb.mouse.pas b/src/driver/hid/usb/driver.hid.usb.mouse.pas index b887b954..c568cdfe 100644 --- a/src/driver/hid/usb/driver.hid.usb.mouse.pas +++ b/src/driver/hid/usb/driver.hid.usb.mouse.pas @@ -13,7 +13,6 @@ unit driver.hid.usb.mouse; interface uses - boot.mgr, driver.bus.usb.types, driver.bus.usb.core, driver.hid.mouse, @@ -23,7 +22,7 @@ uses debug.tracer, io.syslog, core.strings, - core.util, arch.x86.util; + core.util, arch.platform.cpu, arch.platform.diagnostics; procedure init; procedure poll_mice; @@ -82,7 +81,7 @@ function mouse_delta_x(report : Pointer) : sint32; var raw : uint8; begin - raw := PUint8(uint32(report) + 1)^; + raw := PUint8(PtrUInt(report) + 1)^; if raw < 128 then mouse_delta_x := sint32(raw) else @@ -94,7 +93,7 @@ function mouse_delta_y(report : Pointer) : sint32; var raw : uint8; begin - raw := PUint8(uint32(report) + 2)^; + raw := PUint8(PtrUInt(report) + 2)^; if raw < 128 then mouse_delta_y := sint32(raw) else @@ -108,7 +107,7 @@ var begin mouse_scroll := 0; if reportLen < 4 then exit; - raw := PUint8(uint32(report) + 3)^; + raw := PUint8(PtrUInt(report) + 3)^; if raw < 128 then mouse_scroll := sint32(raw) else @@ -417,20 +416,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('USBMouse', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + testSummary('USBMouse', 'USBMOUSE_TESTS_PASSED', 'USBMOUSE_TESTS_FAILED', passed, failed); end; var @@ -555,7 +542,4 @@ begin PrintSummary; end; -initialization - boot.mgr.registerBoot('driver.hid.usb.mouse', @Init, 'USB Mouse Driver', BOOT_MGR_BARRIER_DEVICE); - end. diff --git a/src/driver/storage/ctl/driver.storage.ctl.usb.pas b/src/driver/storage/ctl/driver.storage.ctl.usb.pas index c02e00f9..8db4a530 100644 --- a/src/driver/storage/ctl/driver.storage.ctl.usb.pas +++ b/src/driver/storage/ctl/driver.storage.ctl.usb.pas @@ -28,10 +28,10 @@ procedure UnitTest; implementation -uses boot.mgr, driver.mgr, memory.heap, driver.storage.types, +uses arch.platform.diagnostics, arch.common.legacyirq, driver.mgr, memory.heap, driver.storage.types, driver.storage.mgr, driver.bus.usb.core, driver.bus.usb.types, - proc.mgr, proc.types, arch.x86.bda, arch.x86.isr.tmr0, - core.util, arch.x86.util, io.syslog, io.stdio, core.strings, + proc.mgr, proc.types, arch.platform.process, + core.util, arch.platform.cpu, io.syslog, io.stdio, core.strings, driver.storage.vfs, driver.storage.vol.mgr, core.ds.lists; const @@ -51,6 +51,7 @@ type Status : uint8; end; PCSW = ^TCSW; + PVolumeSlot = ^PStorage_Volume; PMSDevice = ^TMSDevice; TMSDevice = record Next : PMSDevice; @@ -108,16 +109,16 @@ begin end; procedure poll_controller(c : PMSDevice); -var flags : uint32; +var flags : PtrUInt; begin { Poll and its descriptor cleanup must not be preempted by another poll. } - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; if c^.USB^.HC^.fnPoll <> nil then c^.USB^.HC^.fnPoll(c^.USB^.HC); - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); end; function run_transfer(c : PMSDevice) : TUSBTransferStatus; -var started, spins, flags : uint32; submitted : boolean; +var started, spins : uint32; flags : PtrUInt; submitted : boolean; begin run_transfer := tsTimeout; if c^.Offline then exit; @@ -127,23 +128,23 @@ begin c^.InFlight := true; { fnSubmit can configure xHCI endpoints and wait for command completion; never call it under the storage manager's IRQ-disabled dispatch lock. } - asm pushfd; pop flags end; - if c^.USB^.HC^.HCType <> USB_HC_XHCI then asm cli end; + flags := arch.platform.cpu.lock; + if c^.USB^.HC^.HCType = USB_HC_XHCI then arch.platform.cpu.unlock(flags); if c^.Offline then submitted := false else submitted := c^.USB^.HC^.fnSubmit(c^.USB^.HC, @c^.Transfer); - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); if not submitted then begin c^.InFlight := false; exit; end; - started := puint32(@Counters.c32)^; + started := arch.platform.process.timerTicks; spins := 0; while transfer_pending(c) do begin poll_controller(c); if not transfer_pending(c) then break; inc(spins); if (c^.Original = nil) or - (puint32(@Counters.c32)^ - started >= TRANSFER_TICKS) or + (arch.platform.process.timerTicks - started >= TRANSFER_TICKS) or (spins >= 10000000) then begin { No HC cancellation contract exists yet. Fail closed and retain the private transfer/buffers until completion; NEVER free live DMA. } @@ -152,8 +153,9 @@ begin io.syslog.logln('USBMSC', 'Transfer timed out/disconnected; device offline, DMA quarantined.'); exit; end; - asm pushfd; pop flags end; - if (flags and $200) <> 0 then asm hlt end; + flags := arch.platform.cpu.lock; + arch.platform.cpu.unlock(flags); + if (flags and $200) <> 0 then arch.platform.cpu.idle; end; c^.InFlight := false; run_transfer := c^.Transfer.Status; @@ -216,7 +218,7 @@ end; procedure command(c : PMSDevice; opcode, length : uint8; bytes : uint32; input : boolean); begin - memset(uint32(@c^.CBW), 0, sizeof(TCBW)); + memset(PtrUInt(@c^.CBW), 0, sizeof(TCBW)); inc(c^.Tag); c^.CBW.Signature := CBW_SIGNATURE; c^.CBW.Tag := c^.Tag; @@ -242,7 +244,7 @@ begin while offset < c^.CBW.DataLength do begin count := c^.CBW.DataLength - offset; { One bounded data transfer per command, at most one page of DMA. } - status := bulk(c, ep, pointer(uint32(c^.Buffer) + offset), count, actual); + status := bulk(c, ep, pointer(PtrUInt(c^.Buffer) + offset), count, actual); if status = tsStall then begin if not clear_halt(c, ep) then begin recover(c); exit; end; break; @@ -252,7 +254,7 @@ begin if actual < count then break; end; transferred := offset; - memset(uint32(@c^.CSW), 0, sizeof(TCSW)); + memset(PtrUInt(@c^.CSW), 0, sizeof(TCSW)); status := bulk(c, c^.InEP, @c^.CSW, sizeof(TCSW), actual); if status = tsStall then begin if clear_halt(c, c^.InEP) then @@ -273,7 +275,7 @@ begin sense := eIOError; command(c, $03, 6, 18, true); c^.CBW.Command[4] := 18; - memset(uint32(c^.Buffer), 0, 18); + memset(PtrUInt(c^.Buffer), 0, 18); if transport(c, actual) <> 0 then exit; if actual < 14 then exit; if (puint8(c^.Buffer)[0] and $7E) <> $70 then exit; @@ -344,13 +346,13 @@ begin command(c, $00, 6, 0, false); error := execute(c, 0); if error <> eDeviceNotReady then break; - psleep((PIT_INPUT_HZ div PIT_DIVISOR) div 5); + core.util.waitTicks((PIT_INPUT_HZ div PIT_DIVISOR) div 5); end; if error <> eNone then exit; command(c, $25, 10, 8, true); if execute(c, 8) <> eNone then exit; sectors := be32(puint8(c^.Buffer)); - sectorSize := be32(puint8(uint32(c^.Buffer) + 4)); + sectorSize := be32(puint8(PtrUInt(c^.Buffer) + 4)); if not valid_capacity(sectors, sectorSize) then exit; inc(sectors); probe := true; @@ -363,7 +365,7 @@ begin if r^.LBA >= d^.maxSectorCount then exit; if r^.SectorCount > d^.maxSectorCount - r^.LBA then exit; if r^.SectorCount > $FFFFFFFF div d^.sectorSize then exit; - if uint32(r^.Buffer) > $FFFFFFFF - r^.SectorCount * d^.sectorSize then exit; + if PtrUInt(r^.Buffer) > High(PtrUInt) - r^.SectorCount * d^.sectorSize then exit; valid_request := true; end; @@ -407,7 +409,7 @@ begin if r^.RequestType = ioRead then command(c, $28, 10, bytes, true) else begin command(c, $2A, 10, bytes, false); - memcpy(uint32(r^.Buffer) + offset, uint32(c^.Buffer), bytes); + memcpy(PtrUInt(r^.Buffer) + offset, PtrUInt(c^.Buffer), bytes); end; put32(@c^.CBW.Command[2], r^.LBA + doneBlocks); c^.CBW.Command[7] := blocks shr 8; @@ -415,7 +417,7 @@ begin error := execute(c, bytes); if error = eNone then begin if r^.RequestType = ioRead then - memcpy(uint32(c^.Buffer), uint32(r^.Buffer) + offset, bytes); + memcpy(PtrUInt(c^.Buffer), PtrUInt(r^.Buffer) + offset, bytes); inc(doneBlocks, blocks); inc(offset, bytes); end; end; @@ -431,9 +433,9 @@ begin end; procedure disconnect(dev : PUSBDevice); -var c : PMSDevice; flags : uint32; +var c : PMSDevice; flags : PtrUInt; begin - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; c := Devices; while c <> nil do begin if c^.Original = dev then begin @@ -444,7 +446,7 @@ begin end; c := c^.Next; end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); io.syslog.logln('USBMSC', 'Disk disconnected; further I/O rejected.'); end; @@ -459,7 +461,7 @@ begin if c^.Disk^.volumes = nil then exit; i := 0; while i < DL_Size(c^.Disk^.volumes) do begin - v := PStorage_Volume(puint32(DL_Get(c^.Disk^.volumes, i))^); + v := PVolumeSlot(DL_Get(c^.Disk^.volumes, i))^; if (v <> nil) and ((v^.lifecycleFlags and STORAGE_VOLUME_FLAG_MOUNTED) <> 0) then begin if driver.storage.vol.mgr.volume_is_busy(v) then detach_volumes := false else if not driver.storage.vfs.InvalidateVolume(v) then detach_volumes := false; @@ -469,7 +471,7 @@ begin end; procedure worker_loop(ctx : PProcessContext); -var c, next, prev, scan : PMSDevice; flags : uint32; +var c, next, prev, scan : PMSDevice; flags : PtrUInt; begin while true do begin c := Devices; @@ -490,12 +492,12 @@ begin if (c^.Original = nil) and c^.VolumesDetached then begin { Keep the manager's removed-device/volume tombstones stable; release every class-driver allocation once DMA is finished. } - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; prev := nil; scan := Devices; while (scan <> nil) and (scan <> c) do begin prev := scan; scan := scan^.Next; end; if prev = nil then Devices := c^.Next else prev^.Next := c^.Next; if c^.Disk <> nil then c^.Disk^.controllerId0 := 0; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); kfree(void(c^.USB)); kfree_aligned(c); end; end; @@ -506,16 +508,16 @@ begin end; procedure attach_worker(ctx : PProcessContext); -var c : PMSDevice; d : PStorage_Device; sectors, sectorSize, i, flags : uint32; +var c : PMSDevice; d : PStorage_Device; sectors, sectorSize, i : uint32; flags : PtrUInt; claimed : boolean; begin c := PMSDevice(ctx^.Local); { xHCI command submission and manager registration are not reentrant. } repeat - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; claimed := not AttachBusy; if claimed then AttachBusy := true; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); if not claimed then proc.mgr.proc_sleep_ms(1); until claimed; d := PStorage_Device(kalloc(sizeof(TStorage_Device))); @@ -529,13 +531,13 @@ begin io.syslog.logln('USBMSC', 'Probe failed or unsupported disk geometry.'); exit; end; - memset(uint32(d), 0, sizeof(TStorage_Device)); + memset(PtrUInt(d), 0, sizeof(TStorage_Device)); d^.volumes := DL_New(sizeof(pointer)); if d^.volumes = nil then begin kfree(void(d)); c^.Offline := true; c^.Ready := true; c^.Attaching := false; AttachBusy := false; exit; end; d^.controller := ControllerUSB; - d^.controllerId0 := uint32(c); + d^.controllerId0 := PtrUInt(c); d^.writable := true; d^.sectorSize := sectorSize; d^.maxSectorCount := sectors; @@ -547,7 +549,7 @@ begin { Manager copies the record; never keep the temporary descriptor. } i := 0; while i < driver.storage.mgr.get_device_count do begin - if driver.storage.mgr.get_device(i)^.controllerId0 = uint32(c) then begin + if driver.storage.mgr.get_device(i)^.controllerId0 = PtrUInt(c) then begin c^.Disk := driver.storage.mgr.get_device(i); break; end; inc(i); @@ -560,7 +562,8 @@ end; function load(ptr : void) : boolean; var dev : PUSBDevice; c : PMSDevice; - i, flags : uint32; + i : uint32; + flags : PtrUInt; begin load := false; dev := PUSBDevice(ptr); @@ -575,14 +578,14 @@ begin end; c := PMSDevice(kalloc_aligned(sizeof(TMSDevice), 4096)); if c = nil then exit; - memset(uint32(c), 0, sizeof(TMSDevice)); + memset(PtrUInt(c), 0, sizeof(TMSDevice)); c^.USB := PUSBDevice(kalloc(sizeof(TUSBDevice))); c^.Buffer := kalloc_aligned(BUFFER_SIZE, 4096); if (c^.USB = nil) or (c^.Buffer = nil) then begin if c^.USB <> nil then kfree(void(c^.USB)); kfree_aligned(c^.Buffer); kfree_aligned(c); exit; end; - memcpy(uint32(dev), uint32(c^.USB), sizeof(TUSBDevice)); + memcpy(PtrUInt(dev), PtrUInt(c^.USB), sizeof(TUSBDevice)); c^.Original := dev; c^.Attaching := true; for i := 0 to 1 do begin @@ -601,10 +604,10 @@ begin c^.ControlEP.Direction := dirSetup; c^.ControlEP.MaxPacket := dev^.MaxPacket0; { Publish before probing so disconnect can invalidate the private context. } - asm pushfd; cli; pop flags end; + flags := arch.platform.cpu.lock; c^.Next := Devices; Devices := c; dev^.fnDisconnect := @disconnect; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(flags); { The scheduler starts only after boot.mgr.run. Probe and register from a task so partition discovery can wait for the persistent I/O worker. } if proc.mgr.create('usb.attach', @attach_worker, void(c), 1) = nil then begin @@ -652,11 +655,11 @@ begin end; 1: begin if m^.C.CBW.Flags = $80 then begin - memset(uint32(t^.Buffer), $A5, t^.BufferLen); + memset(PtrUInt(t^.Buffer), $A5, t^.BufferLen); case m^.C.CBW.Command[0] of $12: puint8(t^.Buffer)[0] := 0; - $25: begin put32(puint8(t^.Buffer), 8191); put32(puint8(uint32(t^.Buffer)+4), 512); end; - $03: begin memset(uint32(t^.Buffer),0,t^.BufferLen); puint8(t^.Buffer)[0]:=$70; + $25: begin put32(puint8(t^.Buffer), 8191); put32(puint8(PtrUInt(t^.Buffer)+4), 512); end; + $03: begin memset(PtrUInt(t^.Buffer),0,t^.BufferLen); puint8(t^.Buffer)[0]:=$70; if m^.SenseKey = 0 then puint8(t^.Buffer)[2]:=7 else puint8(t^.Buffer)[2]:=m^.SenseKey; end; end; end else begin @@ -720,7 +723,7 @@ begin m := PMock(kalloc(sizeof(TMock))); Assert(m <> nil, 'mock allocation'); if m <> nil then begin - memset(uint32(m), 0, sizeof(TMock)); + memset(PtrUInt(m), 0, sizeof(TMock)); m^.HC.fnSubmit := @mock_submit; m^.HC.HCType := USB_HC_EHCI; m^.HC.PrivData := m; m^.USB.HC := @m^.HC; m^.USB.InterfaceNumber := 3; m^.USB.Endpoints[0].Address := 1; m^.USB.Endpoints[0].Direction := dirIn; @@ -734,7 +737,7 @@ begin Assert(probe(@m^.C, sectors, size) and (sectors = 8192) and (size = 512), 'probe SCSI disk'); command(@m^.C, $28, 10, 512, true); Assert((execute(@m^.C,512) = eNone) and (puint8(m^.C.Buffer)[511] = $A5), 'read data phase'); - command(@m^.C, $2A, 10, 512, false); memset(uint32(m^.C.Buffer),$5A,512); + command(@m^.C, $2A, 10, 512, false); memset(PtrUInt(m^.C.Buffer),$5A,512); Assert((execute(@m^.C,512) = eNone) and m^.GoodWrite, 'write data phase'); m^.Fault := 3; command(@m^.C, $2A, 10, 512, false); Assert(execute(@m^.C,512) = eReadOnly, 'command failure requests sense'); @@ -773,14 +776,13 @@ begin Assert(not valid_request(@m^.Disk,@m^.Request), 'zero-sector request rejected'); m^.Request.LBA := $FFFFFFFE; m^.Request.SectorCount := 4; Assert(not valid_request(@m^.Disk,@m^.Request), 'wrapped LBA rejected'); - m^.Request.LBA := 0; m^.Request.SectorCount := 1; m^.Request.Buffer := pointer($FFFFFF00); + m^.Request.LBA := 0; m^.Request.SectorCount := 1; m^.Request.Buffer := pointer(High(PtrUInt) - $FF); Assert(not valid_request(@m^.Disk,@m^.Request), 'wrapped buffer rejected'); kfree_aligned(m^.C.Buffer); end; kfree(void(m)); end; - io.syslog.log('USBMSC', 'Tests passed: '); io.syslog.writeint(passed); - io.syslog.writestring(' failed: '); io.syslog.writeintln(failed); + testSummary('USBMSC', 'USBMSC_TESTS_PASSED', 'USBMSC_TESTS_FAILED', passed, failed); end; procedure test_command(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); @@ -800,6 +802,4 @@ begin driver.mgr.register_driver('USB Mass Storage', @id, @load); end; -initialization - boot.mgr.registerBoot('driver.storage.ctl.usb', @init, 'USB Mass Storage Driver', BOOT_MGR_BARRIER_DEVICE); end.