diff --git a/src/machine/machine_rp2040_usb.go b/src/machine/machine_rp2040_usb.go index 627afd808f..2ef08fcbe4 100644 --- a/src/machine/machine_rp2040_usb.go +++ b/src/machine/machine_rp2040_usb.go @@ -67,7 +67,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { if !ok { // Stall endpoint? - sendStallViaEPIn(0) + USBDev.SetStallEPIn(0) } } diff --git a/src/machine/machine_rp2350_usb.go b/src/machine/machine_rp2350_usb.go index 5a298b1afd..d29a3ae980 100644 --- a/src/machine/machine_rp2350_usb.go +++ b/src/machine/machine_rp2350_usb.go @@ -70,7 +70,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { if !ok { // Stall endpoint? - sendStallViaEPIn(0) + USBDev.SetStallEPIn(0) } } diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index 414fedb5b6..96d8cda4f7 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -21,26 +21,33 @@ func initEndpoint(ep, config uint32) { offset := ep*2*usbBufferLen + 0x100 val |= offset + // Bulk and interrupt endpoints must have their Packet ID reset to DATA0 when un-stalled. + epXPIDReset[ep] = false // Default to false in case an endpoint is re-initialized. + switch config { case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: val |= usbEpControlEndpointTypeInterrupt _usbDPSRAM.EPxControl[ep].In.Set(val) + epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: val |= usbEpControlEndpointTypeBulk _usbDPSRAM.EPxControl[ep].Out.Set(val) _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) + epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut: val |= usbEpControlEndpointTypeInterrupt _usbDPSRAM.EPxControl[ep].Out.Set(val) _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) + epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: val |= usbEpControlEndpointTypeBulk _usbDPSRAM.EPxControl[ep].In.Set(val) + epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_CONTROL: val |= usbEpControlEndpointTypeControl @@ -109,7 +116,12 @@ func handleEndpointRx(ep uint32) []byte { } func handleEndpointRxComplete(ep uint32) { - epXdata0[ep] = !epXdata0[ep] + setEPDataPID(ep, !epXdata0[ep]) +} + +// Set the USB endpoint Packet ID to DATA0 or DATA1. +func setEPDataPID(ep uint32, dataOne bool) { + epXdata0[ep] = dataOne if epXdata0[ep] || ep == 0 { _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) } @@ -138,7 +150,8 @@ func sendViaEPIn(ep uint32, data []byte, count int) { _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) } -func sendStallViaEPIn(ep uint32) { +// Set ENDPOINT_HALT/stall status on a USB IN endpoint. +func (dev *USBDevice) SetStallEPIn(ep uint32) { // Prepare buffer control register value if ep == 0 { armEPZeroStall() @@ -149,6 +162,37 @@ func sendStallViaEPIn(ep uint32) { _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) } +// Set ENDPOINT_HALT/stall status on a USB OUT endpoint. +func (dev *USBDevice) SetStallEPOut(ep uint32) { + if ep == 0 { + panic("SetStallEPOut: EP0 OUT not valid") + } + val := uint32(usbBuf0CtrlStall) + _usbDPSRAM.EPxBufferControl[ep&0x7F].Out.Set(val) +} + +// Clear the ENDPOINT_HALT/stall on a USB IN endpoint. +func (dev *USBDevice) ClearStallEPIn(ep uint32) { + ep = ep & 0x7F + val := uint32(usbBuf0CtrlStall) + _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) + if epXPIDReset[ep] { + // Reset the PID to DATA0 + setEPDataPID(ep&0x7F, false) + } +} + +// Clear the ENDPOINT_HALT/stall on a USB OUT endpoint. +func (dev *USBDevice) ClearStallEPOut(ep uint32) { + ep = ep & 0x7F + val := uint32(usbBuf0CtrlStall) + _usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val) + if epXPIDReset[ep] { + // Reset the PID to DATA0 + setEPDataPID(ep, false) + } +} + type usbDPSRAM struct { // Note that EPxControl[0] is not EP0Control but 8-byte setup data. EPxControl [16]usbEndpointControlRegister @@ -173,9 +217,10 @@ type usbBuffer struct { } var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - setupBytes [8]byte + _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) + epXdata0 [16]bool + epXPIDReset [16]bool + setupBytes [8]byte ) func (d *usbDPSRAM) setupBytes() []byte { diff --git a/src/machine/usb.go b/src/machine/usb.go index 1c577b5f6e..8663348157 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -123,6 +123,7 @@ var ( usbTxHandler [usb.NumberOfEndpoints]func() usbRxHandler [usb.NumberOfEndpoints]func([]byte) usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool + usbStallHandler [usb.NumberOfEndpoints]func(usb.Setup) bool endPoints = []uint32{ usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, @@ -212,6 +213,12 @@ func handleStandardSetup(setup usb.Setup) bool { if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP isRemoteWakeUpEnabled = false } else if setup.WValueL == 0 { // ENDPOINTHALT + if idx := setup.WIndex & 0x7F; idx < usb.NumberOfEndpoints && usbStallHandler[idx] != nil { + // Host has requested to clear an endpoint stall. If the request is addressed to + // an endpoint with a configured StallHandler, forward the message on. + // The 0x7F mask is used to clear the direction bit from the endpoint number + return usbStallHandler[idx](setup) + } isEndpointHalt = false } SendZlp() @@ -221,6 +228,12 @@ func handleStandardSetup(setup usb.Setup) bool { if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP isRemoteWakeUpEnabled = true } else if setup.WValueL == 0 { // ENDPOINTHALT + if idx := setup.WIndex & 0x7F; idx < usb.NumberOfEndpoints && usbStallHandler[idx] != nil { + // Host has requested to stall an endpoint. If the request is addressed to + // an endpoint with a configured StallHandler, forward the message on. + // The 0x7F mask is used to clear the direction bit from the endpoint number + return usbStallHandler[idx](setup) + } isEndpointHalt = true } SendZlp() @@ -320,6 +333,9 @@ func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointC usbRxHandler[ep.Index] = ep.RxHandler } } + if ep.StallHandler != nil { + usbStallHandler[ep.Index] = ep.StallHandler + } } for _, s := range setup { diff --git a/src/machine/usb/config.go b/src/machine/usb/config.go index ef7cd31530..4ce7cd803a 100644 --- a/src/machine/usb/config.go +++ b/src/machine/usb/config.go @@ -1,11 +1,12 @@ package usb type EndpointConfig struct { - Index uint8 - IsIn bool - TxHandler func() - RxHandler func([]byte) - Type uint8 + Index uint8 + IsIn bool + TxHandler func() + RxHandler func([]byte) + StallHandler func(Setup) bool + Type uint8 } type SetupConfig struct {