From 0f3d0c3b02474049de294f491466e426ced1c591 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 26 Aug 2025 20:40:08 -0400 Subject: [PATCH 1/4] feat: allow bidirectional usb endpoint numbers --- builder/sizes_test.go | 2 +- src/machine/machine_atsamd21_usb.go | 80 +++++++++++++++++-------- src/machine/machine_atsamd51_usb.go | 46 ++++++++++----- src/machine/machine_nrf52840_usb.go | 24 +++++--- src/machine/machine_rp2_usb.go | 81 +++++++++++++++++--------- src/machine/usb.go | 11 ++-- src/machine/usb/cdc/cdc.go | 4 +- src/machine/usb/descriptor/cdc.go | 6 +- src/machine/usb/descriptor/endpoint.go | 59 +++++++++++-------- src/machine/usb/descriptor/hid.go | 10 ++-- src/machine/usb/descriptor/joystick.go | 10 ++-- src/machine/usb/descriptor/midi.go | 33 ++++++----- src/machine/usb/descriptor/msc.go | 6 +- src/machine/usb/usb.go | 16 ++--- 14 files changed, 242 insertions(+), 146 deletions(-) diff --git a/builder/sizes_test.go b/builder/sizes_test.go index f4274708da..df7fae3bd7 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -44,7 +44,7 @@ func TestBinarySize(t *testing.T) { // microcontrollers {"hifive1b", "examples/echo", 4580, 280, 0, 2264}, {"microbit", "examples/serial", 2928, 388, 8, 2272}, - {"wioterminal", "examples/pininterrupt", 7387, 1489, 116, 6912}, + {"wioterminal", "examples/pininterrupt", 7444, 1500, 116, 6592}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/machine/machine_atsamd21_usb.go b/src/machine/machine_atsamd21_usb.go index 7b9d2e14f8..6a30db98dd 100644 --- a/src/machine/machine_atsamd21_usb.go +++ b/src/machine/machine_atsamd21_usb.go @@ -20,19 +20,24 @@ const ( usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14 usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF - NumberOfUSBEndpoints = 8 + NumberOfUSBEndpoints = 6 ) var ( - endPoints = []uint32{ + inEndpoints = []uint32{ + usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, + usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), + usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), + usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In + usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + } + outEndpoints = []uint32{ usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out + usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out } ) @@ -188,7 +193,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { // Now the actual transfer handlers, ignore endpoint number 0 (setup) var i uint32 - for i = 1; i < uint32(len(endPoints)); i++ { + for i = 1; i < NumberOfUSBEndpoints; i++ { // Check if endpoint has a pending interrupt epFlags := getEPINTFLAG(i) setEPINTFLAG(i, epFlags) @@ -197,7 +202,8 @@ func handleUSBIRQ(intr interrupt.Interrupt) { if usbRxHandler[i] == nil || usbRxHandler[i](buf) { AckUsbOutTransfer(i) } - } else if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 { + } + if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 { if usbTxHandler[i] != nil { usbTxHandler[i]() } @@ -215,8 +221,9 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos)) + setEPCFGEPType1(ep, (usb.ENDPOINT_TYPE_INTERRUPT + 1)) + // Set interrupt enable setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1) case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: @@ -227,7 +234,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos)) + setEPCFGEPType0(ep, (usb.ENDPOINT_TYPE_BULK + 1)) // receive interrupts when current transfer complete setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0) @@ -246,7 +253,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos)) + setEPCFGEPType0(ep, (usb.ENDPOINT_TYPE_INTERRUPT + 1)) // receive interrupts when current transfer complete setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0) @@ -265,11 +272,12 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos)) + setEPCFGEPType1(ep, (usb.ENDPOINT_TYPE_BULK + 1)) // NAK on endpoint IN, the bank is not yet filled in. setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY) + // Set interrupt enable setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1) case usb.ENDPOINT_TYPE_CONTROL: @@ -281,7 +289,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)< 0 { + } + if (epFlags & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) > 0 { if usbTxHandler[i] != nil { usbTxHandler[i]() } @@ -218,8 +224,9 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos)) + setEPCFGEPType1(ep, (usb.ENDPOINT_TYPE_INTERRUPT + 1)) + // Set interrupt enable setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1) case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: @@ -230,7 +237,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos)) + setEPCFGEPType0(ep, (usb.ENDPOINT_TYPE_BULK + 1)) // receive interrupts when current transfer complete setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0) @@ -249,7 +256,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos)) + setEPCFGEPType0(ep, (usb.ENDPOINT_TYPE_INTERRUPT + 1)) // receive interrupts when current transfer complete setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0) @@ -268,11 +275,12 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos)) + setEPCFGEPType1(ep, (usb.ENDPOINT_TYPE_BULK + 1)) // NAK on endpoint IN, the bank is not yet filled in. setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY) + // Set interrupt enable setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1) case usb.ENDPOINT_TYPE_CONTROL: @@ -284,7 +292,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)< 0 outDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPOUT1<<(i-1)) > 0 @@ -191,7 +196,8 @@ func handleUSBIRQ(interrupt.Interrupt) { if usbTxHandler[i] != nil { usbTxHandler[i]() } - } else if outDataDone { + } + if outDataDone { enterCriticalSection() nrf.USBD.EPOUT[i].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[i])))) count := nrf.USBD.SIZE.EPOUT[i].Get() @@ -202,7 +208,7 @@ func handleUSBIRQ(interrupt.Interrupt) { } // ENDEPOUT[n] events - for i := 0; i < len(endPoints); i++ { + for i := 0; i < len(outEndpoints); i++ { if nrf.USBD.EVENTS_ENDEPOUT[i].Get() > 0 { nrf.USBD.EVENTS_ENDEPOUT[i].Set(0) buf := handleEndpointRx(uint32(i)) diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index 297cc9d9cf..7b922235bf 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -8,7 +8,8 @@ import ( "unsafe" ) -const NumberOfUSBEndpoints = 8 +// If inEndpoints or outEndpoints is added to, this must be updated. +const NumberOfUSBEndpoints = 6 var ( sendOnEP0DATADONE struct { @@ -17,15 +18,20 @@ var ( pid uint32 } - endPoints = []uint32{ + inEndpoints = []uint32{ + usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, + usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), + usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), + usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In + usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + } + outEndpoints = []uint32{ usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out + usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out } ) @@ -35,32 +41,34 @@ func initEndpoint(ep, config uint32) { 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. + // Default to false in case an endpoint is re-initialized. + inEpXPIDReset[ep] = false + outEpXPIDReset[ep] = false switch config { case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: val |= usbEpControlEndpointTypeInterrupt _usbDPSRAM.EPxControl[ep].In.Set(val) - epXPIDReset[ep] = true + inEpXPIDReset[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 + outEpXPIDReset[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 + outEpXPIDReset[ep] = true case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: val |= usbEpControlEndpointTypeBulk _usbDPSRAM.EPxControl[ep].In.Set(val) - epXPIDReset[ep] = true + inEpXPIDReset[ep] = true case usb.ENDPOINT_TYPE_CONTROL: val |= usbEpControlEndpointTypeControl @@ -94,7 +102,7 @@ func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { } else { sendOnEP0DATADONE.offset = 0 } - epXdata0[ep] = true + inEpXdata0[ep] = true } sendViaEPIn(ep, data, count) @@ -131,13 +139,24 @@ func handleEndpointRx(ep uint32) []byte { // AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. func AckUsbOutTransfer(ep uint32) { ep = ep & 0x7F - setEPDataPID(ep, !epXdata0[ep]) + setEPOutDataPID(ep, !outEpXdata0[ep]) +} + +// Set the USB endpoint Packet ID to DATA0 or DATA1. +func setEPInDataPID(ep uint32, dataOne bool) { + ep = ep & 0x7F + inEpXdata0[ep] = dataOne + if inEpXdata0[ep] || ep == 0 { + _usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlData1Pid) + } + + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) } // Set the USB endpoint Packet ID to DATA0 or DATA1. -func setEPDataPID(ep uint32, dataOne bool) { - epXdata0[ep] = dataOne - if epXdata0[ep] || ep == 0 { +func setEPOutDataPID(ep uint32, dataOne bool) { + outEpXdata0[ep] = dataOne + if outEpXdata0[ep] || ep == 0 { _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) } @@ -151,18 +170,20 @@ func SendZlp() { func sendViaEPIn(ep uint32, data []byte, count int) { // Prepare buffer control register value val := uint32(count) | usbBuf0CtrlAvail + // Drop the endpoint in bit (0x80) + ep = ep & 0x7F // DATA0 or DATA1 - epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] - if !epXdata0[ep&0x7F] { + inEpXdata0[ep] = !inEpXdata0[ep] + if !inEpXdata0[ep] { val |= usbBuf0CtrlData1Pid } // Mark as full val |= usbBuf0CtrlFull - copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) + copy(_usbDPSRAM.EPxBuffer[ep].Buffer0[:], data[:count]) + _usbDPSRAM.EPxBufferControl[ep].In.Set(val) } // Set ENDPOINT_HALT/stall status on a USB IN endpoint. @@ -193,9 +214,9 @@ func (dev *USBDevice) ClearStallEPIn(ep uint32) { ep = ep & 0x7F val := uint32(usbBuf0CtrlStall) _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) - if epXPIDReset[ep] { + if inEpXPIDReset[ep] { // Reset the PID to DATA0 - setEPDataPID(ep, false) + setEPInDataPID(ep, false) } } @@ -204,12 +225,14 @@ func (dev *USBDevice) ClearStallEPOut(ep uint32) { ep = ep & 0x7F val := uint32(usbBuf0CtrlStall) _usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val) - if epXPIDReset[ep] { + if outEpXPIDReset[ep] { // Reset the PID to DATA0 - setEPDataPID(ep, false) + setEPOutDataPID(ep, false) } } +// RP2040: See datasheet section 4.1.2.7.2 +// RP2350: See datasheet section 12.7.3.7.2 type usbDPSRAM struct { // Note that EPxControl[0] is not EP0Control but 8-byte setup data. EPxControl [16]usbEndpointControlRegister @@ -234,10 +257,12 @@ type usbBuffer struct { } var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - epXPIDReset [16]bool - setupBytes [8]byte + _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) + inEpXdata0 [16]bool + outEpXdata0 [16]bool + inEpXPIDReset [16]bool + outEpXPIDReset [16]bool + setupBytes [8]byte ) func (d *usbDPSRAM) setupBytes() []byte { diff --git a/src/machine/usb.go b/src/machine/usb.go index 434ee0f1b8..d30cb3acb1 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -245,8 +245,11 @@ func handleStandardSetup(setup usb.Setup) bool { case usb.SET_CONFIGURATION: if setup.BmRequestType&usb.REQUEST_RECIPIENT == usb.REQUEST_DEVICE { - for i := 1; i < len(endPoints); i++ { - initEndpoint(uint32(i), endPoints[i]) + for i := 1; i < len(inEndpoints); i++ { + initEndpoint(uint32(i), inEndpoints[i]) + } + for i := 1; i < len(outEndpoints); i++ { + initEndpoint(uint32(i), outEndpoints[i]) } usbConfiguration = setup.WValueL @@ -312,12 +315,12 @@ func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointC for _, ep := range epSettings { if ep.IsIn { - endPoints[ep.Index] = uint32(ep.Type | usb.EndpointIn) + inEndpoints[ep.Index] = uint32(ep.Type | usb.EndpointIn) if ep.TxHandler != nil { usbTxHandler[ep.Index] = ep.TxHandler } } else { - endPoints[ep.Index] = uint32(ep.Type | usb.EndpointOut) + outEndpoints[ep.Index] = uint32(ep.Type | usb.EndpointOut) if ep.RxHandler != nil { usbRxHandler[ep.Index] = func(b []byte) bool { ep.RxHandler(b) diff --git a/src/machine/usb/cdc/cdc.go b/src/machine/usb/cdc/cdc.go index f180535df1..6888fa4f67 100644 --- a/src/machine/usb/cdc/cdc.go +++ b/src/machine/usb/cdc/cdc.go @@ -2,8 +2,8 @@ package cdc const ( cdcEndpointACM = 1 - cdcEndpointOut = 2 - cdcEndpointIn = 3 + cdcEndpointOut = 1 + cdcEndpointIn = 2 ) // New returns USBCDC struct. diff --git a/src/machine/usb/descriptor/cdc.go b/src/machine/usb/descriptor/cdc.go index ec72186e3a..8b427016f2 100644 --- a/src/machine/usb/descriptor/cdc.go +++ b/src/machine/usb/descriptor/cdc.go @@ -160,9 +160,9 @@ var CDC = Descriptor{ ClassSpecificCDCCallManagement.Bytes(), ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), - EndpointEP1IN.Bytes(), + EndpointCDCACMIN.Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointCDCOUT.Bytes(), + EndpointCDCIN.Bytes(), }), } diff --git a/src/machine/usb/descriptor/endpoint.go b/src/machine/usb/descriptor/endpoint.go index 57a17060c4..a9ec1d2224 100644 --- a/src/machine/usb/descriptor/endpoint.go +++ b/src/machine/usb/descriptor/endpoint.go @@ -29,92 +29,103 @@ var EndpointEP1IN = EndpointType{ data: endpointEP1IN[:], } -var endpointEP2OUT = [endpointTypeLen]byte{ +var endpointEP1OUT = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x02, // EndpointAddress + 0x01, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH 0x00, // Interval } -var EndpointEP2OUT = EndpointType{ - data: endpointEP2OUT[:], +var EndpointEP1OUT = EndpointType{ + data: endpointEP1OUT[:], } -var endpointEP3IN = [endpointTypeLen]byte{ +var endpointEP2IN = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x83, // EndpointAddress + 0x82, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH 0x00, // Interval } -var EndpointEP3IN = EndpointType{ - data: endpointEP3IN[:], +var EndpointEP2IN = EndpointType{ + data: endpointEP2IN[:], } -var endpointEP4IN = [endpointTypeLen]byte{ +var endpointEP2OUT = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x84, // EndpointAddress + 0x02, // EndpointAddress 0x03, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH 0x01, // Interval } -var EndpointEP4IN = EndpointType{ - data: endpointEP4IN[:], +var EndpointEP2OUT = EndpointType{ + data: endpointEP2OUT[:], } -var endpointEP5OUT = [endpointTypeLen]byte{ +var endpointEP3IN = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x05, // EndpointAddress + 0x83, // EndpointAddress 0x03, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH 0x01, // Interval } -var EndpointEP5OUT = EndpointType{ - data: endpointEP5OUT[:], +var EndpointEP3IN = EndpointType{ + data: endpointEP3IN[:], } // Mass Storage Class bulk in endpoint -var endpointMSCIN = [endpointTypeLen]byte{ +var endpointEP5IN = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x86, // EndpointAddress + 0x85, // EndpointAddress TransferTypeBulk, // Attributes 0x40, // MaxPacketSizeL (64 bytes) 0x00, // MaxPacketSizeH 0x00, // Interval } -var EndpointMSCIN = EndpointType{ - data: endpointMSCIN[:], +var EndpointEP5IN = EndpointType{ + data: endpointEP5IN[:], } // Mass Storage Class bulk out endpoint -var endpointMSCOUT = [endpointTypeLen]byte{ +var endpointEP4OUT = [endpointTypeLen]byte{ endpointTypeLen, TypeEndpoint, - 0x07, // EndpointAddress + 0x04, // EndpointAddress TransferTypeBulk, // Attributes 0x40, // MaxPacketSizeL (64 bytes) 0x00, // MaxPacketSizeH 0x00, // Interval } -var EndpointMSCOUT = EndpointType{ - data: endpointMSCOUT[:], +var EndpointEP4OUT = EndpointType{ + data: endpointEP4OUT[:], } +// Aliases for easier reuse +var ( + EndpointCDCACMIN = &EndpointEP1IN + EndpointCDCOUT = &EndpointEP1OUT + EndpointCDCIN = &EndpointEP2IN + EndpointHIDOUT = &EndpointEP2OUT + EndpointHIDIN = &EndpointEP3IN + EndpointMSCOUT = &EndpointEP4OUT + EndpointMSCIN = &EndpointEP5IN +) + const ( endpointTypeLen = 7 ) diff --git a/src/machine/usb/descriptor/hid.go b/src/machine/usb/descriptor/hid.go index 06b9801530..cf121605bc 100644 --- a/src/machine/usb/descriptor/hid.go +++ b/src/machine/usb/descriptor/hid.go @@ -121,14 +121,14 @@ var CDCHID = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointCDCACMIN.Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointCDCOUT.Bytes(), + EndpointCDCIN.Bytes(), InterfaceHID.Bytes(), ClassHID.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), + EndpointHIDIN.Bytes(), + EndpointHIDOUT.Bytes(), }), HID: map[uint16][]byte{ 2: Append([][]byte{ // Update ClassLength in classHID whenever the array length is modified! diff --git a/src/machine/usb/descriptor/joystick.go b/src/machine/usb/descriptor/joystick.go index 65756e0d63..b1d71fc2ca 100644 --- a/src/machine/usb/descriptor/joystick.go +++ b/src/machine/usb/descriptor/joystick.go @@ -131,14 +131,14 @@ var CDCJoystick = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointCDCACMIN.Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointCDCOUT.Bytes(), + EndpointCDCIN.Bytes(), InterfaceHIDJoystick.Bytes(), ClassHIDJoystick.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), + EndpointHIDIN.Bytes(), + EndpointHIDOUT.Bytes(), }), HID: map[uint16][]byte{}, } diff --git a/src/machine/usb/descriptor/midi.go b/src/machine/usb/descriptor/midi.go index fad81f31d5..4c4744506b 100644 --- a/src/machine/usb/descriptor/midi.go +++ b/src/machine/usb/descriptor/midi.go @@ -3,7 +3,7 @@ package descriptor var interfaceAssociationMIDI = [interfaceAssociationTypeLen]byte{ interfaceAssociationTypeLen, TypeInterfaceAssociation, - 0x02, // EndpointAddress + 0x01, // EndpointAddress 0x02, // Attributes 0x01, // MaxPacketSizeL 0x01, // MaxPacketSizeH @@ -171,10 +171,10 @@ var ClassSpecificMIDIInEndpoint = ClassSpecificType{ const endpointMIDITypeLen = 9 -var endpointEP6IN = [endpointMIDITypeLen]byte{ +var endpointEP4IN = [endpointMIDITypeLen]byte{ endpointMIDITypeLen, TypeEndpoint, - 0x86, // EndpointAddress + 0x84, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH @@ -183,14 +183,14 @@ var endpointEP6IN = [endpointMIDITypeLen]byte{ 0x00, // sync address } -var EndpointEP6IN = EndpointType{ - data: endpointEP6IN[:], +var EndpointEP4IN = EndpointType{ + data: endpointEP4IN[:], } -var endpointEP7OUT = [endpointMIDITypeLen]byte{ +var endpointEP3OUT = [endpointMIDITypeLen]byte{ endpointMIDITypeLen, TypeEndpoint, - 0x07, // EndpointAddress + 0x03, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH @@ -199,10 +199,15 @@ var endpointEP7OUT = [endpointMIDITypeLen]byte{ 0x00, // sync address } -var EndpointEP7OUT = EndpointType{ - data: endpointEP7OUT[:], +var EndpointEP3OUT = EndpointType{ + data: endpointEP3OUT[:], } +var ( + EndpointMIDIIN = &EndpointEP4IN + EndpointMIDIOUT = &EndpointEP3OUT +) + var configurationCDCMIDI = [configurationTypeLen]byte{ configurationTypeLen, TypeConfiguration, @@ -228,10 +233,10 @@ var CDCMIDI = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointCDCACMIN.Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointCDCOUT.Bytes(), + EndpointCDCIN.Bytes(), InterfaceAssociationMIDI.Bytes(), InterfaceAudio.Bytes(), ClassSpecificAudioInterface.Bytes(), @@ -241,9 +246,9 @@ var CDCMIDI = Descriptor{ ClassSpecificMIDIInJack2.Bytes(), ClassSpecificMIDIOutJack1.Bytes(), ClassSpecificMIDIOutJack2.Bytes(), - EndpointEP7OUT.Bytes(), + EndpointMIDIOUT.Bytes(), ClassSpecificMIDIOutEndpoint.Bytes(), - EndpointEP6IN.Bytes(), + EndpointMIDIIN.Bytes(), ClassSpecificMIDIInEndpoint.Bytes(), }), } diff --git a/src/machine/usb/descriptor/msc.go b/src/machine/usb/descriptor/msc.go index 55c6ddd857..939fa393d2 100644 --- a/src/machine/usb/descriptor/msc.go +++ b/src/machine/usb/descriptor/msc.go @@ -63,10 +63,10 @@ var MSC = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointCDCACMIN.Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointCDCOUT.Bytes(), + EndpointCDCIN.Bytes(), InterfaceAssociationMSC.Bytes(), InterfaceMSC.Bytes(), EndpointMSCIN.Bytes(), diff --git a/src/machine/usb/usb.go b/src/machine/usb/usb.go index 40983a9a3c..f45b52a018 100644 --- a/src/machine/usb/usb.go +++ b/src/machine/usb/usb.go @@ -73,14 +73,14 @@ const ( // Endpoint CONTROL_ENDPOINT = 0 CDC_ENDPOINT_ACM = 1 - CDC_ENDPOINT_OUT = 2 - CDC_ENDPOINT_IN = 3 - HID_ENDPOINT_IN = 4 // for Interrupt In - HID_ENDPOINT_OUT = 5 // for Interrupt Out - MIDI_ENDPOINT_IN = 6 // for Bulk In - MIDI_ENDPOINT_OUT = 7 // for Bulk Out - MSC_ENDPOINT_IN = 6 // for Bulk In - MSC_ENDPOINT_OUT = 7 // for Bulk Out + CDC_ENDPOINT_OUT = 1 + CDC_ENDPOINT_IN = 2 + HID_ENDPOINT_OUT = 2 // for Interrupt Out + HID_ENDPOINT_IN = 3 // for Interrupt In + MIDI_ENDPOINT_OUT = 3 // for Bulk Out + MIDI_ENDPOINT_IN = 4 // for Bulk In + MSC_ENDPOINT_OUT = 4 // for Bulk Out + MSC_ENDPOINT_IN = 5 // for Bulk In // bmRequestType REQUEST_HOSTTODEVICE = 0x00 From 05c92e410fb8997eb8ebd99565e0fdf75fc50ee9 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 27 Aug 2025 08:36:39 -0400 Subject: [PATCH 2/4] chore: move endpoints and NumberOfUSBEndpoints to usb.go --- builder/sizes_test.go | 2 +- src/machine/machine_atsamd21_usb.go | 22 +--------------------- src/machine/machine_atsamd51_usb.go | 22 +--------------------- src/machine/machine_nrf52840_usb.go | 20 +------------------- src/machine/machine_rp2_usb.go | 19 ------------------- src/machine/usb.go | 22 ++++++++++++++++++++-- 6 files changed, 24 insertions(+), 83 deletions(-) diff --git a/builder/sizes_test.go b/builder/sizes_test.go index df7fae3bd7..dffbcb0ade 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -44,7 +44,7 @@ func TestBinarySize(t *testing.T) { // microcontrollers {"hifive1b", "examples/echo", 4580, 280, 0, 2264}, {"microbit", "examples/serial", 2928, 388, 8, 2272}, - {"wioterminal", "examples/pininterrupt", 7444, 1500, 116, 6592}, + {"wioterminal", "examples/pininterrupt", 7442, 1502, 116, 6592}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/machine/machine_atsamd21_usb.go b/src/machine/machine_atsamd21_usb.go index 6a30db98dd..c8c52f4d78 100644 --- a/src/machine/machine_atsamd21_usb.go +++ b/src/machine/machine_atsamd21_usb.go @@ -19,26 +19,6 @@ const ( usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14 usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF - - NumberOfUSBEndpoints = 6 -) - -var ( - inEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - } - outEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } ) // Configure the USB peripheral. The config is here for compatibility with the UART interface. @@ -193,7 +173,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { // Now the actual transfer handlers, ignore endpoint number 0 (setup) var i uint32 - for i = 1; i < NumberOfUSBEndpoints; i++ { + for i = 1; i < uint32(NumberOfUSBEndpoints); i++ { // Check if endpoint has a pending interrupt epFlags := getEPINTFLAG(i) setEPINTFLAG(i, epFlags) diff --git a/src/machine/machine_atsamd51_usb.go b/src/machine/machine_atsamd51_usb.go index 2a9f9026f9..0654c9364b 100644 --- a/src/machine/machine_atsamd51_usb.go +++ b/src/machine/machine_atsamd51_usb.go @@ -19,26 +19,6 @@ const ( usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14 usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF - - NumberOfUSBEndpoints = 6 -) - -var ( - inEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - } - outEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } ) // Configure the USB peripheral. The config is here for compatibility with the UART interface. @@ -196,7 +176,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { // Now the actual transfer handlers, ignore endpoint number 0 (setup) var i uint32 - for i = 1; i < NumberOfUSBEndpoints; i++ { + for i = 1; i < uint32(NumberOfUSBEndpoints); i++ { // Check if endpoint has a pending interrupt epFlags := getEPINTFLAG(i) setEPINTFLAG(i, epFlags) diff --git a/src/machine/machine_nrf52840_usb.go b/src/machine/machine_nrf52840_usb.go index 2b009cc6ad..be6e696e4e 100644 --- a/src/machine/machine_nrf52840_usb.go +++ b/src/machine/machine_nrf52840_usb.go @@ -11,8 +11,6 @@ import ( "unsafe" ) -const NumberOfUSBEndpoints = 6 - var ( sendOnEP0DATADONE struct { ptr *byte @@ -22,22 +20,6 @@ var ( epinen uint32 epouten uint32 easyDMABusy volatile.Register8 - - inEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - } - outEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } ) // enterCriticalSection is used to protect access to easyDMA - only one thing @@ -188,7 +170,7 @@ func handleUSBIRQ(interrupt.Interrupt) { epDataStatus := nrf.USBD.EPDATASTATUS.Get() nrf.USBD.EPDATASTATUS.Set(epDataStatus) var i uint32 - for i = 1; i < NumberOfUSBEndpoints; i++ { + for i = 1; i < uint32(NumberOfUSBEndpoints); i++ { // Check if endpoint has a pending interrupt inDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPIN1<<(i-1)) > 0 outDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPOUT1<<(i-1)) > 0 diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index 7b922235bf..be47fd65b9 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -8,31 +8,12 @@ import ( "unsafe" ) -// If inEndpoints or outEndpoints is added to, this must be updated. -const NumberOfUSBEndpoints = 6 - var ( sendOnEP0DATADONE struct { offset int data []byte pid uint32 } - - inEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - } - outEndpoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } ) func initEndpoint(ep, config uint32) { diff --git a/src/machine/usb.go b/src/machine/usb.go index d30cb3acb1..021a1b7032 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -119,11 +119,29 @@ var udd_ep_out_cache_buffer [NumberOfUSBEndpoints][64]uint8 // must be revisited. var usb_trans_buffer [255]uint8 +const NumberOfUSBEndpoints = max(len(inEndpoints), len(outEndpoints)) + var ( usbTxHandler [NumberOfUSBEndpoints]func() usbRxHandler [NumberOfUSBEndpoints]func([]byte) bool usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool usbStallHandler [NumberOfUSBEndpoints]func(usb.Setup) bool + + inEndpoints = [...]uint32{ + usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, + usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), + usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), + usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In + usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + usb.MSC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In + } + outEndpoints = [...]uint32{ + usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, + usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), + usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out + usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out + usb.MSC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out + } ) // sendDescriptor creates and sends the various USB descriptor types that @@ -202,7 +220,7 @@ 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 < NumberOfUSBEndpoints && usbStallHandler[idx] != nil { + if idx := setup.WIndex & 0x7F; idx < uint16(NumberOfUSBEndpoints) && 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 @@ -217,7 +235,7 @@ 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 < NumberOfUSBEndpoints && usbStallHandler[idx] != nil { + if idx := setup.WIndex & 0x7F; idx < uint16(NumberOfUSBEndpoints) && 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 From d9d2d023e4b22ade3dc0bd4d6110fabeea33c1e8 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 27 Aug 2025 09:29:07 -0400 Subject: [PATCH 3/4] chore: make names more consistent --- src/machine/machine_rp2_usb.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index be47fd65b9..dbc55fcd76 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -83,7 +83,7 @@ func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { } else { sendOnEP0DATADONE.offset = 0 } - inEpXdata0[ep] = true + inEpXdata0[ep] = usbPIDData1 } sendViaEPIn(ep, data, count) @@ -120,11 +120,11 @@ func handleEndpointRx(ep uint32) []byte { // AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. func AckUsbOutTransfer(ep uint32) { ep = ep & 0x7F - setEPOutDataPID(ep, !outEpXdata0[ep]) + setOutEPDataPID(ep, !outEpXdata0[ep]) } // Set the USB endpoint Packet ID to DATA0 or DATA1. -func setEPInDataPID(ep uint32, dataOne bool) { +func setInEPDataPID(ep uint32, dataOne usbPID) { ep = ep & 0x7F inEpXdata0[ep] = dataOne if inEpXdata0[ep] || ep == 0 { @@ -135,7 +135,7 @@ func setEPInDataPID(ep uint32, dataOne bool) { } // Set the USB endpoint Packet ID to DATA0 or DATA1. -func setEPOutDataPID(ep uint32, dataOne bool) { +func setOutEPDataPID(ep uint32, dataOne usbPID) { outEpXdata0[ep] = dataOne if outEpXdata0[ep] || ep == 0 { _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) @@ -197,7 +197,7 @@ func (dev *USBDevice) ClearStallEPIn(ep uint32) { _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) if inEpXPIDReset[ep] { // Reset the PID to DATA0 - setEPInDataPID(ep, false) + setInEPDataPID(ep, usbPIDData0) } } @@ -208,7 +208,7 @@ func (dev *USBDevice) ClearStallEPOut(ep uint32) { _usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val) if outEpXPIDReset[ep] { // Reset the PID to DATA0 - setEPOutDataPID(ep, false) + setOutEPDataPID(ep, usbPIDData0) } } @@ -237,10 +237,18 @@ type usbBuffer struct { Buffer1 [usbBufferLen]byte } +// USB Packet ID +type usbPID bool + +const ( + usbPIDData0 usbPID = false + usbPIDData1 usbPID = true +) + var ( _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - inEpXdata0 [16]bool - outEpXdata0 [16]bool + inEpXdata0 [16]usbPID + outEpXdata0 [16]usbPID inEpXPIDReset [16]bool outEpXPIDReset [16]bool setupBytes [8]byte From ba2479398e7305ec2925844288d8f3372e35e998 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 27 Aug 2025 14:12:29 -0400 Subject: [PATCH 4/4] chore: fix copy/paste typo --- src/machine/machine_rp2_usb.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index dbc55fcd76..c537e9d219 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -119,7 +119,6 @@ func handleEndpointRx(ep uint32) []byte { // AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. func AckUsbOutTransfer(ep uint32) { - ep = ep & 0x7F setOutEPDataPID(ep, !outEpXdata0[ep]) } @@ -131,7 +130,7 @@ func setInEPDataPID(ep uint32, dataOne usbPID) { _usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlData1Pid) } - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) + _usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlAvail) } // Set the USB endpoint Packet ID to DATA0 or DATA1. @@ -169,6 +168,7 @@ func sendViaEPIn(ep uint32, data []byte, count int) { // Set ENDPOINT_HALT/stall status on a USB IN endpoint. func (dev *USBDevice) SetStallEPIn(ep uint32) { + // Drop the endpoint in bit (0x80) ep = ep & 0x7F // Prepare buffer control register value if ep == 0 { @@ -182,7 +182,6 @@ func (dev *USBDevice) SetStallEPIn(ep uint32) { // Set ENDPOINT_HALT/stall status on a USB OUT endpoint. func (dev *USBDevice) SetStallEPOut(ep uint32) { - ep = ep & 0x7F if ep == 0 { panic("SetStallEPOut: EP0 OUT not valid") } @@ -192,6 +191,7 @@ func (dev *USBDevice) SetStallEPOut(ep uint32) { // Clear the ENDPOINT_HALT/stall on a USB IN endpoint. func (dev *USBDevice) ClearStallEPIn(ep uint32) { + // Drop the endpoint in bit (0x80) ep = ep & 0x7F val := uint32(usbBuf0CtrlStall) _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) @@ -203,7 +203,6 @@ func (dev *USBDevice) ClearStallEPIn(ep uint32) { // 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 outEpXPIDReset[ep] {