fix(native-usb): prevent transmit-bank starvation and retain battery telemetry
This commit is contained in:
parent
a407e84a39
commit
a699a6920b
16 changed files with 342 additions and 82 deletions
|
|
@ -4,6 +4,17 @@
|
|||
usb_hw_t native_test_usb;
|
||||
usb_device_dpram_t native_test_dpram;
|
||||
sio_hw_t native_test_sio;
|
||||
bool native_test_abort_stuck;
|
||||
uint32_t native_test_interrupt_mask;
|
||||
static bool servicing_interrupt;
|
||||
|
||||
void native_test_service_interrupt(void) {
|
||||
if (native_test_interrupt_mask || servicing_interrupt || !usb_hw->ints) return;
|
||||
servicing_interrupt = true;
|
||||
usb_interrupt();
|
||||
usb_hw->ints = 0;
|
||||
servicing_interrupt = false;
|
||||
}
|
||||
|
||||
void probe_router_init(uint32_t hz) { (void)hz; }
|
||||
void probe_router_core1(void) {}
|
||||
|
|
@ -36,6 +47,9 @@ void native_test_initialize(void) {
|
|||
memset(usb_hw,0,sizeof(*usb_hw));
|
||||
memset(usb_dpram,0,sizeof(*usb_dpram));
|
||||
event_head = event_tail = 0;
|
||||
native_test_abort_stuck = false;
|
||||
native_test_interrupt_mask = 0;
|
||||
servicing_interrupt = false;
|
||||
failed = bus_suspended = bank_restore_pending = false;
|
||||
bank_lock = spin_lock_instance(0);
|
||||
active_device = default_device = 0;
|
||||
|
|
@ -49,6 +63,8 @@ static bool select_slot(uint8_t slot) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool native_test_select(uint8_t slot) { return select_slot(slot); }
|
||||
|
||||
void native_test_drain(void) { native_hub_task(); }
|
||||
|
||||
bool native_test_setup(uint8_t slot, const tusb_control_request_t* request, bool drain) {
|
||||
|
|
@ -56,14 +72,16 @@ bool native_test_setup(uint8_t slot, const tusb_control_request_t* request, bool
|
|||
memcpy(usb_dpram->setup_packet,request,sizeof(*request));
|
||||
usb_hw->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
|
||||
usb_hw->ints = USB_INTS_SETUP_REQ_BITS;
|
||||
usb_interrupt();
|
||||
usb_hw->ints = 0;
|
||||
native_test_service_interrupt();
|
||||
if (drain) native_hub_task();
|
||||
return !failed && devices[slot].control.stage != STALLED;
|
||||
}
|
||||
|
||||
void native_test_hold_abort(bool hold) { native_test_abort_stuck = hold; }
|
||||
|
||||
bool native_test_out(uint8_t slot, const uint8_t* data, uint16_t length, bool drain) {
|
||||
if (!select_slot(slot)) return false;
|
||||
if (usb_hw->abort & 2u) return false;
|
||||
uint32_t value = buffer_regs()[1];
|
||||
if (!(value & USB_BUF_CTRL_AVAIL) || (value & USB_BUF_CTRL_STALL) ||
|
||||
length > (value & USB_BUF_CTRL_LEN_MASK)) return false;
|
||||
|
|
@ -71,14 +89,14 @@ bool native_test_out(uint8_t slot, const uint8_t* data, uint16_t length, bool dr
|
|||
buffer_regs()[1] = (value & ~(USB_BUF_CTRL_AVAIL | USB_BUF_CTRL_LEN_MASK)) | length;
|
||||
usb_hw->buf_status = 2;
|
||||
usb_hw->ints = USB_INTS_BUFF_STATUS_BITS;
|
||||
usb_interrupt();
|
||||
usb_hw->ints = 0;
|
||||
native_test_service_interrupt();
|
||||
if (drain) native_hub_task();
|
||||
return !failed && devices[slot].control.stage != STALLED;
|
||||
}
|
||||
|
||||
bool native_test_in(uint8_t slot, uint8_t* data, uint16_t* length, bool drain) {
|
||||
if (!select_slot(slot)) return false;
|
||||
if (usb_hw->abort & 1u) return false;
|
||||
uint32_t value = buffer_regs()[0];
|
||||
if (!(value & USB_BUF_CTRL_AVAIL) || !(value & USB_BUF_CTRL_FULL) ||
|
||||
(value & USB_BUF_CTRL_STALL)) return false;
|
||||
|
|
@ -87,17 +105,35 @@ bool native_test_in(uint8_t slot, uint8_t* data, uint16_t* length, bool drain) {
|
|||
buffer_regs()[0] = value & ~USB_BUF_CTRL_AVAIL;
|
||||
usb_hw->buf_status = 1;
|
||||
usb_hw->ints = USB_INTS_BUFF_STATUS_BITS;
|
||||
usb_interrupt();
|
||||
usb_hw->ints = 0;
|
||||
native_test_service_interrupt();
|
||||
if (drain) native_hub_task();
|
||||
return !failed && devices[slot].control.stage != STALLED;
|
||||
}
|
||||
|
||||
bool native_test_private_in(uint8_t slot, uint8_t endpoint, uint8_t* data, uint16_t* length) {
|
||||
if (slot < 1 || slot > 2 || (endpoint != 0x81 && endpoint != 0x82)) return false;
|
||||
// A host token selects the bank, but cannot wait for a foreground task.
|
||||
if (!native_hub_select_device(addresses[slot],slot,UINT32_MAX / 2)) return false;
|
||||
unsigned channel = (endpoint & 15u) * 2u;
|
||||
uint32_t control = endpoint_regs()[channel - 2u];
|
||||
uint32_t value = buffer_regs()[channel];
|
||||
if (!(control & EP_CTRL_ENABLE_BITS) || !(value & USB_BUF_CTRL_AVAIL) ||
|
||||
!(value & USB_BUF_CTRL_FULL) || (value & USB_BUF_CTRL_STALL)) return false;
|
||||
*length = value & USB_BUF_CTRL_LEN_MASK;
|
||||
if (*length > PACKET) return false;
|
||||
if (*length) copy_from_usb(data,
|
||||
(const volatile uint8_t*)USBCTRL_DPRAM_BASE + (control & 0xffffu), *length);
|
||||
buffer_regs()[channel] = value & ~USB_BUF_CTRL_AVAIL;
|
||||
usb_hw->buf_status |= 1u << channel;
|
||||
usb_hw->ints |= USB_INTS_BUFF_STATUS_BITS;
|
||||
native_test_service_interrupt();
|
||||
return !failed;
|
||||
}
|
||||
|
||||
void native_test_bus_reset(bool drain) {
|
||||
usb_hw->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
|
||||
usb_hw->ints = USB_INTS_BUS_RESET_BITS;
|
||||
usb_interrupt();
|
||||
usb_hw->ints = 0;
|
||||
native_test_service_interrupt();
|
||||
if (drain) native_hub_task();
|
||||
// Assign fixture addresses after reset, independently of EP0 state.
|
||||
addresses[0] = 0; addresses[1] = 1; addresses[2] = 2;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue