Run init_fido() at boot to fix USB hang on CTAPHID_INIT - #273
Open
DmitriyLyalyuev wants to merge 1 commit into
Open
DmitriyLyalyuev wants to merge 1 commit into
DmitriyLyalyuev wants to merge 1 commit into
Conversation
The CTAPHID_INIT handler in pico-keys-sdk calls init_fido(), which on
the first invocation after power-up runs scan_files_fido() (potentially
generating ECDSA keys and X.509 cert on factory state) and init_otp()
(increments OTP session counter and calls flash_commit). The deferred
flash sector erase that follows blocks USB IRQs for ~50-150 ms via
flash_range_erase + save_and_disable_interrupts in low_flash_task.
Symptom on macOS Tahoe (and reproducible with raw hidapi):
1. Device enumerates correctly: PrimaryUsagePage=0xF1D0, two HID
interfaces (FIDO + Keyboard).
2. First CTAPHID_INIT responds, but slowly (~215 ms instead of
typical 5-10 ms).
3. Every subsequent CTAPHID_INIT in the same session times out with
no IN report; macOS then refuses further OUT writes
(kIOUSB-style errors) until physical re-plug.
4. Chrome, Safari and Firefox all show "waiting for security key"
because their initial CTAPHID handshake fails.
Fix: override the WEAK picokey_init() hook (called from main() before
core0_loop starts USB enumeration) and invoke init_fido() there. The
static `scanned` flag in init_otp() and the file_has_data() checks in
scan_files_fido() make subsequent calls cheap, so the first
CTAPHID_INIT no longer triggers flash work inside the set_report
callback. Verified with five back-to-back CTAPHID_INIT calls via
python-hidapi: stable 32 ms latency, no stalls.
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
The CTAPHID_INIT handler in
pico-keys-sdkcallsinit_fido(), which on first invocation after power-up runsscan_files_fido()andinit_otp().init_otp()increments the OTP session counter and callsflash_commit(). The resulting deferred flash sector erase blocks USB IRQs for ~50–150 ms viaflash_range_erase+save_and_disable_interruptsinsidelow_flash_task.Effect: the first
CTAPHID_INITresponds slowly (~215 ms instead of the typical 5–10 ms), and every subsequentCTAPHID_INITin the same session times out — the IN endpoint stalls and macOS refuses further OUT writes until physical re-plug. Result: Chrome, Safari, and Firefox all sit on "waiting for security key" because their initial CTAPHID handshake never completes.Fix: override the
WEAK picokey_init()hook (called frommain()beforecore0_loopstarts USB enumeration) and invokeinit_fido()there. The staticscannedflag ininit_otp()plus thefile_has_data()checks inscan_files_fido()make the in-handler call cheap, so flash work no longer runs inside theset_reportcallback.Reproduction (before)
Hardware: Pico Key Ultimate RP2040 16 MB, current
pico-fidov7.6 +pico-keys-sdk8.6, macOS 26 (Tahoe).Before:
After:
After re-flash with this patch, registering and authenticating with the device on
webauthn.ioand real services (GitHub, Google) works in Chrome, Safari, and Firefox.Notes
src/fido/fido.c; the SDK side (pico-keys-sdk) is untouched. TheWEAK picokey_init()hook inpico-keys-sdk/src/main.cwas already designed for exactly this kind of override.init_fido()calls (still triggered from the SDK's CTAPHID_INIT handler on every channel re-init) are idempotent thanks to the staticscannedflag and existing file-presence checks, so no behavior change there.init_fido()call from the CTAPHID_INIT handler entirely, but that is intentionally left out of this PR to keep the change minimal.Test plan