Conversation
For full-speed and low-speed interrupt/iso endpoints, bInterval is a LINEAR polling period in milliseconds per USB 2.0 section 9.6.6 (range 1..255), not a log-scale exponent the way it is for high-speed endpoints. EHCI's periodic-schedule InterruptTail[] is indexed by log2 of the polling interval -- slot i polls at 2^i frames = 2^i ms. Pre-patch, the full-speed branch treated bInterval as a direct slot index after just clamping to EHCI_INTR_COUNT (= 8). A typical HID keyboard with bInterval=10 (10ms requested) was placed on slot 7 (128ms polling) -- 12.8x slower than the device requested. Keys weren't necessarily silent, just laggy / under-sampled. This was uncovered during the Gap-J investigation (HID interrupt-in via EHCI high-speed hub doesn't deliver keystrokes). H5 is a real bug regardless of whether it's the primary cause of the Gap-J keyboard-non-functional symptom -- a device polled at 128ms instead of 10ms is degraded UX even when transfers otherwise succeed. Fix: compute floor(log2(bInterval)) for the FS/LS path and use that+1 as the clamped value. Examples after fix: bInterval=10 -> slot 3 (8ms) bInterval=8 -> slot 3 (8ms) bInterval=1 -> slot 0 (1ms) bInterval=255 -> slot 7 (128ms, clamped) Closest-power-of-2-not-exceeding the request, which is the conventional EHCI scheduler placement for non-aligned intervals. High-speed bInterval handling is unchanged. It has its own quirk (2x over-polling vs USB spec due to a -4 vs -3 exponent offset) but that's harmless (extra bandwidth, no functional issue) and out of scope for this commit. Also: tighten the stale assertion at EHCI_RemoveEndpoint's INTR/ISOC branch from '<= 11' (correct when EHCI_INTR_COUNT was 11) to '>= 1 && <= EHCI_INTR_COUNT' (currently 8). Adjacent dead-code cleanup since the array bounds and the assertion got out of sync during an earlier refactor. Refs: USB 2.0 spec section 9.6.6 (endpoint descriptors / bInterval semantics by speed) Refs: EHCI 1.0 spec section 4.2 (Periodic Schedule) Refs: USBDDOS Gap-J diagnostic investigation (May 2026) Signed-off-by: Arthur Clark <tekguru@tekguru.us>
F-RECAP-1: USB_MSC_InitDevice computed a /1024 MaxLBA for capacity display and clobbered the same field, breaking later bounds checks for small media; introduce MaxLBA_K local.
F-AUDIT-1: DPMI_DMAMalloc fixed at source (no offset arithmetic on NULL malloc return). Ten callsites in hub.c, ohci.c, uhci.c, ehci.c, usb.c converted from assert(p) (no-op in RELEASE) or unchecked deref to graceful if-null return + _LOG.
F-AUDIT-3: five printf sites in MSC install/mount/teardown paired with _LOG so error/success info appears in COM1 regardless of CTTY state. Includes brace fix preventing if/else regression.
F-AUDIT-2 (visibility half): when USB_InitDevice rejects a device because the HC or global capacity is exhausted, emit a _LOG line identifying which limit was hit and on which port. Helps users diagnose silent enumeration failures in hub configurations. The original F-AUDIT-2 also raised USB_MAX_DEVICE_COUNT from 4 to 8 on Watcom/Borland builds; that change was found to break RELEASE-watcom on no-device tests (any increase above 4 triggers a silent hang in usb.c init flow). Deferred to a separate investigation branch pending root-cause analysis. Binary is byte-identical to stock alpha.3 in RELEASE; new strings appear only in DEBUG builds.
F-MEMMGR-DOC: documents the DPMI host requirement difference between USBDDOS.EXE (Watcom, embedded PM) and USBDDOSP.EXE (DJGPP, needs external DPMI host); CWSDPMI tight-XMS failure mode and resolutions; per-DOS table for FreeDOS 1.3/1.4, MS-DOS 6.22/7.x, DR-DOS 7.x, PC DOS 2000.
EHCI: fix periodic schedule slot index for full-speed/low-speed bInterval
MSC: preserve un-scaled MaxLBA for sector bounds checks
OOM hardening: DMAMalloc returns NULL cleanly, callsites check
MSC: pair install-path printfs with _LOG for COM1 capture
usb: log USB device-capacity rejects to COM1
README: add Memory managers and XMS section
… NAK-forever devices)
… correct wrong-constant guard The free-slot loop in USB_InitDevice had no bounds check: with all slots valid it indexed one past Devices[] and memset an adjacent function-pointer table, GP-faulting on the 5th concurrent device (docking station). Guard the scan so a full pool refuses enumeration with a log line instead of corrupting memory. Raise USB_MAX_DEVICE_COUNT to 8 for the 16-bit build (~576 bytes resident, measured) to cover dock topologies. Remove the dead DeviceCount field whose guard could never fire, and correct the remaining guard to HCD_MAX_DEVICE_COUNT. Field-validated on IBM 300GL dock (Issue crazii#2).
…t V86 mode switch (fixes GP fault)
Bounded control-transfer wait + UHCI abort (fixes enumeration hang on NAK-forever devices)
Device pool: bounds-guard the free-slot scan, raise 16-bit pool 4->8, correct wrong-constant guard
DPMI: defer nested hardware IRQs to avoid reentering the non-reentrant V86 mode switch (fixes GP fault)
LXXero
marked this pull request as draft
September 14, 2026 05:22
…der, port power
The Gap 6 quirk for the ALi M5237 skipped not just reading HcFmInterval but
also writing it, at three sites (InitController, its INITRESET retry, and the
OHCI_ISR unrecoverable-error recovery), and its substitute default 0x2EDF had
no FSMPS. After HCR the register stayed 0x00002EDF, the FSMPS verify failed,
the retry could not help because it skipped the write too, and the root hub
never enumerated anything ("no USB device found"). Real M5237 silicon shows
the post-reset read is safe (Linux's ohci_run/periodic_reinit reads and writes
it on this chip); only the pre-reset handoff read is worth avoiding.
Three changes, confined to OHCI_HasFmIntervalLockup() chips except where noted:
- Gap 6: keep the read-skip but always write a full HcFmInterval after HCR:
FIT | FSMPS(FI)<<16 | FI = 0xA7782EDF (FSMPS = (6*(FI-210))/7 per OHCI
1.0a 7.3.1 / Linux FSMP()). FIT is a guaranteed toggle since HCR clears it.
- Gap 6b: mirror Linux's unconditional OHCI_QUIRK_INITRESET for this chip -
reprogram HcFmInterval (FIT toggled, as periodic_reinit) and HcPeriodicStart
right after the controller goes USBOPERATIONAL.
- Gap 6c (all chips): always assert SetGlobalPower with a plain W1S write
before the per-port SetPortPower loop. With PowerSwitchingMode set, per-port
writes only affect ports whose PortPowerControlMask bit is set (OHCI 7.4.3);
the M5237 reports PSM=1 with PPCM=0 (HcRhDescriptorB=0), so its ports are
gang-controlled, PPS stayed 0 and a bus-powered device could never be seen.
Linux ohci_run() writes RH_HS_LPSC unconditionally.
Debug builds also log a pre-enumeration snapshot (HcControl, HcCommandStatus,
HcFmInterval, HcPeriodicStart, HcFmNumber sampled twice 2 ms apart, both root
hub descriptors, HcRhStatus and both HcRhPortStatus registers).
Verified on an ASUS P5A-B (ALi M1543C, Win98 SE real-mode DOS) with logs
captured over COM1. Original alpha: "FmInterval=00002edf ... didn't latch;
INITRESET retry / still won't latch", no device. Gap 6 alone: latch errors
gone, still no device. Gap 6b: HcControl=0xBC, FmInterval=0x27782EDF,
FmNumber advancing, but Port1=Port2=0x00000000 (PPS=0). With Gap 6c:
RhDescB=0x00000000, Port1=0x00000100 (PPS=1), Port2=0x00010301 (CCS=1,
PPS=1, low-speed), and a USB HID boot-protocol mouse enumerates fully
(address set, descriptors read, config 1, two class-3 endpoints, boot
protocol, HID driver started, driver goes resident).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vCAmSU6DrcjpXWvjyXcPd
…the packet instead of hanging the machine The keyboard/mouse bridge injects bytes into the 8042 with cmd D2/D3 and then spins in unbounded while loops until the resident PS/2 driver's IRQ handler reads port 60h. The mouse finalizer does this with every IRQ except 12 masked and the keyboard port disabled, so if the byte is never drained (no PS/2 mouse driver resident, its aux-IRQ enable cleared by a driver re-probe, a KBC that doesn't raise IRQ12 for D3, ...) the box hard-hangs: no keyboard, no Ctrl-Alt-Del. Seen on real hardware (ASUS P5A-B, ALi M1543C KBC) right after the first successful OHCI enumeration on that chipset. Bound all three waits (~256K port reads, >=250ms on any PC). On timeout the mouse path drains the stuck byte, aborts the rest of the packet, re-enables the keyboard port and restores the IRQ mask; the DEBUG build logs the drop count to COM1 so a non-draining bridge is diagnosable instead of fatal. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vCAmSU6DrcjpXWvjyXcPd
LXXero
force-pushed
the
fix/ali-m5237-fminterval-write
branch
from
September 14, 2026 05:31
5ad896f to
8b27d2e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On the ALi/ULi M5237 OHCI controller (PCI
10b9:5237— the USB block in the ALi M1543C southbridge) the driver reported "no USB device found": the root hub never enumerated anything. This fixes the three OHCI init bugs behind that. A USB HID mouse now enumerates fully on real M5237 hardware.Test hardware
ASUS P5A-B (Super Socket 7), ALi M1543C, VIA C3, Windows 98 SE, real-mode DOS. Diagnostics captured over COM1 (DEBUG build).
Root cause & fixes (all
USBDDOS/HCD/ohci.c)The existing "Gap 6" quirk for this chip skipped writing
HcFmInterval, not just reading it, at three sites (InitController, its INITRESET retry, OHCI_ISR recovery), and its substitute default0x2EDFhad no FSMPS. After HCR the register stayed0x00002EDF, the FSMPS verify failed, and the retry couldn't help because it skipped the write too. Real silicon shows the post-reset read is fine (Linux'sohci_run/periodic_reinitread+write it here); only the pre-reset handoff read is worth avoiding.HcFmIntervalafter HCR:FIT | FSMPS(FI)<<16 | FI=0xA7782EDF(FSMPS = (6*(FI-210))/7, OHCI 1.0a 7.3.1 / LinuxFSMP()).OHCI_QUIRK_INITRESETfor this chip: reprogramHcFmInterval(toggling FIT, asperiodic_reinit) +HcPeriodicStartafter the controller reaches USBOPERATIONAL.SetGlobalPowerbefore the per-portSetPortPowerloop. The M5237 reportsPowerSwitchingMode=1butPortPowerControlMask=0(HcRhDescriptorB=0), so its ports are gang-controlled and the per-port writes were no-ops; PPS stayed 0 and no bus-powered device could be seen. Linuxohci_run()writesRH_HS_LPSCunconditionally.Evidence (COM1, real M5237)
FmInterval=00002edf ... didn't latch; INITRESET retry / still won't latch, no deviceHcControl=0xBC,FmInterval=0x27782EDF, frame timer advancing — butPort1=Port2=0(PPS=0)Port1=0x00000100(PPS=1),Port2=0x00010301(CCS=1, low-speed), then full enumeration — set address, descriptors, config 1, 2× class-3 endpoints, HID boot protocol, driver started.DEBUG builds now also log a pre-enumeration register snapshot.
Scope / not addressed here
This fixes OHCI enumeration. It does not touch the PS/2 8042 bridge (
USB_HID_Mouse_GenerateSample): on this box, after enumeration, delivering samples via 8042 cmd0xD3hard-hangs the machine — the keyboard port is left disabled (0xAD) and thewhile(inp(0x64)&…)waits are unbounded, so it spins forever if nothing drains port0x60. That appears to be a separate, pre-existing issue and is left for a follow-up.Developed with AI assistance (noted in the commit trailer).