switch-pico/tests/native_hub_stubs/hardware_stub.h
Joey Yakimowich-Payne 80b788099b feat(native-usb): add 32-frame HD gameplay rumble and USB flight diagnostics
Preserve native frequency/amplitude timelines for DualSense PCM output,
remove the unsupported 64-frame path, and retain compatibility rumble for
other controllers. Use the validated 300 MHz sampling phase and restrict
non-bondable Classic discovery autoconnect to previously paired peers.

Buffer native-hub UART stdout and release USB IRQs around port-reset
callbacks. Add observer liveness and pre-SETUP root-response observations
without changing recovery behavior. Cover transport and haptics boundaries.

Record the user-accepted 0.108 trial: controls remained responsive and
rumble felt fine. Instrumentation changes timing; the disconnect root
cause and long-term reliability remain unqualified.

Validation: 624 tests, 11 affected firmware/probe builds, and on-device
concurrent USB and HD-auto-start checks. Private captures, generated
images, and unrelated working-tree files are intentionally excluded.
2026-09-19 17:03:46 -06:00

141 lines
5.6 KiB
C

#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define __not_in_flash_func(name) name
#define __no_inline_not_in_flash_func(name) __attribute__((noinline)) name
#define __force_inline inline __attribute__((always_inline))
#define __dmb() ((void)0)
typedef struct { unsigned unused; } spin_lock_t;
typedef struct {
void (*out_chars)(const char*, int);
void (*out_flush)(void);
} stdio_driver_t;
extern stdio_driver_t stdio_uart;
extern uint32_t native_test_interrupt_mask;
void native_test_service_interrupt(void);
static inline uint32_t save_and_disable_interrupts(void) {
uint32_t flags = native_test_interrupt_mask;
native_test_interrupt_mask = 1;
return flags;
}
static inline void restore_interrupts(uint32_t flags) {
native_test_interrupt_mask = flags;
native_test_service_interrupt();
}
static inline uint32_t spin_lock_blocking(spin_lock_t* lock) {
(void)lock; return save_and_disable_interrupts();
}
static inline void spin_unlock(spin_lock_t* lock, uint32_t flags) {
(void)lock; restore_interrupts(flags);
}
static inline bool spin_try_lock_unsafe(spin_lock_t* lock) { (void)lock; return true; }
static inline void spin_unlock_unsafe(spin_lock_t* lock) { (void)lock; }
static inline int spin_lock_claim_unused(bool required) { (void)required; return 0; }
static inline spin_lock_t* spin_lock_instance(unsigned index) {
static spin_lock_t lock; (void)index; return &lock;
}
static inline void hw_clear_bits(volatile uint32_t* address, uint32_t bits) { *address &= ~bits; }
typedef struct {
volatile uint32_t ints, sie_status, buf_status, dev_addr_ctrl, inte;
volatile uint32_t ep_stall_arm, muxing, phy_direct, phy_direct_override;
volatile uint32_t pwr, main_ctrl, sie_ctrl, ep_nak_stall_status;
volatile uint32_t ep_tx_error, ep_rx_error;
volatile uint32_t abort, abort_done;
volatile uint32_t sm_state, sof_rd, intr, dev_sm_watchdog, nak_poll;
} usb_hw_t;
typedef struct { volatile uint32_t in, out; } usb_pair_t;
typedef struct {
uint8_t setup_packet[8];
usb_pair_t ep_ctrl[15];
usb_pair_t ep_buf_ctrl[16];
uint8_t ep0_buf_a[64];
uint8_t padding[3776];
} usb_device_dpram_t;
typedef struct { volatile uint32_t mtime, gpio_hi_oe_clr, gpio_hi_in; } sio_hw_t;
extern usb_hw_t native_test_usb;
extern usb_device_dpram_t native_test_dpram;
extern sio_hw_t native_test_sio;
#define usb_hw (&native_test_usb)
#define usb_dpram (&native_test_dpram)
#define sio_hw (&native_test_sio)
#define USBCTRL_DPRAM_BASE ((uintptr_t)usb_dpram)
#define USB_DPRAM_SIZE sizeof(*usb_dpram)
extern bool native_test_abort_stuck;
static inline void hw_set_bits(volatile uint32_t* address, uint32_t bits) {
*address |= bits;
if (address == &usb_hw->abort && !native_test_abort_stuck)
usb_hw->abort_done |= bits;
}
#define USB_BUF_CTRL_LEN_MASK 0x3ffu
#define USB_BUF_CTRL_AVAIL (1u << 10)
#define USB_BUF_CTRL_STALL (1u << 11)
#define USB_BUF_CTRL_SEL (1u << 12)
#define USB_BUF_CTRL_DATA1_PID (1u << 13)
#define USB_BUF_CTRL_LAST (1u << 14)
#define USB_BUF_CTRL_FULL (1u << 15)
#define EP_CTRL_ENABLE_BITS (1u << 31)
#define EP_CTRL_INTERRUPT_PER_BUFFER (1u << 29)
#define EP_CTRL_INTERRUPT_ON_NAK (1u << 16)
#define EP_CTRL_BUFFER_TYPE_LSB 26
#define USB_INTS_BUS_RESET_BITS (1u << 0)
#define USB_INTS_SETUP_REQ_BITS (1u << 1)
#define USB_INTS_DEV_SUSPEND_BITS (1u << 2)
#define USB_INTS_DEV_RESUME_FROM_HOST_BITS (1u << 3)
#define USB_INTS_BUFF_STATUS_BITS (1u << 4)
#define USB_SIE_STATUS_SETUP_REC_BITS (1u << 0)
#define USB_SIE_STATUS_BUS_RESET_BITS (1u << 1)
#define USB_SIE_STATUS_SUSPENDED_BITS (1u << 2)
#define USB_SIE_STATUS_RESUME_BITS (1u << 3)
#define USB_USB_MUXING_TO_PHY_BITS 1u
#define USB_USB_MUXING_SOFTCON_BITS 2u
#define USB_USB_MUXING_USBPHY_AS_GPIO_BITS 4u
#define SIO_GPIO_HI_IN_USB_DP_BITS 1u
#define SIO_GPIO_HI_IN_USB_DM_BITS 2u
#define USB_USBPHY_DIRECT_DP_PULLUP_EN_BITS 1u
#define USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS 1u
#define USB_USB_PWR_VBUS_DETECT_BITS 1u
#define USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS 2u
#define USB_MAIN_CTRL_CONTROLLER_EN_BITS 1u
#define USB_SIE_CTRL_EP0_INT_1BUF_BITS 1u
#define USB_SIE_CTRL_PULLUP_EN_BITS 2u
#define RESETS_RESET_USBCTRL_BITS 1u
#define USBCTRL_IRQ 0u
#define clk_sys 0u
#ifdef SWITCH_PICO_SYS_CLOCK_MHZ
#define NATIVE_TEST_SYS_CLOCK_HZ (SWITCH_PICO_SYS_CLOCK_MHZ * 1000000u)
#else
#define NATIVE_TEST_SYS_CLOCK_HZ 240000000u
#endif
static inline uint32_t clock_get_hz(unsigned clock) { (void)clock; return NATIVE_TEST_SYS_CLOCK_HZ; }
static inline void reset_block(uint32_t mask) { (void)mask; }
static inline void unreset_block_wait(uint32_t mask) { (void)mask; }
static inline void multicore_launch_core1(void (*entry)(void)) { (void)entry; }
static inline void irq_set_exclusive_handler(unsigned irq, void (*fn)(void)) { (void)irq; (void)fn; }
static inline void irq_set_priority(unsigned irq, unsigned priority) { (void)irq; (void)priority; }
static inline void irq_set_enabled(unsigned irq, bool enabled) { (void)irq; (void)enabled; }
static inline uint32_t time_us_32(void) { return 1000000u; }
static inline bool watchdog_enable_caused_reboot(void) { return false; }
static inline void watchdog_enable(uint32_t ms, bool pause) { (void)ms; (void)pause; }
static inline void watchdog_update(void) {}
static inline void stdio_init_all(void) {}
static inline void sleep_ms(uint32_t ms) { (void)ms; }
static inline void tight_loop_contents(void) {}
static inline void pico_get_unique_board_id_string(char* buffer, size_t size) {
if (size) buffer[0] = '\0';
}
#ifdef __cplusplus
extern "C" {
#endif
void reset_usb_boot(uint32_t gpio_mask, uint32_t disable_mask);
int probe_debug_printf(const char* format, ...);
#ifdef __cplusplus
}
#endif