Skip to content

Commit e7f4a69

Browse files
committed
fix(usb): support bidirectional endpoints on RP2 and SAMD21/51.
Remap CDC and MSC endpoints to share physical endpoint numbers. This change separates IN/OUT directional states for RP2 endpoints to prevent cross-talk, ensures SAMD21 and SAMD51 endpoint configuration merging does not overwrite bidirectionally shared registers, implements missing SAMD endpoint stall and clear methods, and corrects SAMD interrupt loop bounds to iterate over physical endpoint numbers rather than dynamic configuration entries.
1 parent 1b9fa48 commit e7f4a69

7 files changed

Lines changed: 152 additions & 77 deletions

File tree

src/machine/machine_atsamd21_usb.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
175175

176176
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
177177
var i uint32
178-
for i = 1; i < uint32(len(endPoints)); i++ {
178+
for i = 1; i < NumberOfUSBEndpoints; i++ {
179179
// Check if endpoint has a pending interrupt
180180
epFlags := getEPINTFLAG(i)
181181
setEPINTFLAG(i, epFlags)
@@ -193,6 +193,8 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
193193
}
194194

195195
func initEndpoint(ep, config uint32) {
196+
// Note: Both IN (Bank 1) and OUT (Bank 0) configurations share the same EPCFG register.
197+
// We must use getEPCFG(ep) | ... to avoid clearing/disabling the opposite direction.
196198
switch config {
197199
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
198200
// set packet size
@@ -202,7 +204,7 @@ func initEndpoint(ep, config uint32) {
202204
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
203205

204206
// set endpoint type
205-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
207+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_INTERRUPT+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
206208

207209
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1)
208210

@@ -214,7 +216,7 @@ func initEndpoint(ep, config uint32) {
214216
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
215217

216218
// set endpoint type
217-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
219+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
218220

219221
// receive interrupts when current transfer complete
220222
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0)
@@ -233,7 +235,7 @@ func initEndpoint(ep, config uint32) {
233235
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
234236

235237
// set endpoint type
236-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
238+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_INTERRUPT+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
237239

238240
// receive interrupts when current transfer complete
239241
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0)
@@ -252,7 +254,7 @@ func initEndpoint(ep, config uint32) {
252254
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
253255

254256
// set endpoint type
255-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
257+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
256258

257259
// NAK on endpoint IN, the bank is not yet filled in.
258260
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
@@ -650,3 +652,19 @@ func setEPINTENSET(ep uint32, val uint8) {
650652
return
651653
}
652654
}
655+
656+
func (dev *USBDevice) SetStallEPIn(ep uint32) {
657+
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_STALLRQ1)
658+
}
659+
660+
func (dev *USBDevice) SetStallEPOut(ep uint32) {
661+
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_STALLRQ0)
662+
}
663+
664+
func (dev *USBDevice) ClearStallEPIn(ep uint32) {
665+
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_STALLRQ1)
666+
}
667+
668+
func (dev *USBDevice) ClearStallEPOut(ep uint32) {
669+
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_STALLRQ0)
670+
}

src/machine/machine_atsamd51_usb.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
178178

179179
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
180180
var i uint32
181-
for i = 1; i < uint32(len(endPoints)); i++ {
181+
for i = 1; i < NumberOfUSBEndpoints; i++ {
182182
// Check if endpoint has a pending interrupt
183183
epFlags := getEPINTFLAG(i)
184184
setEPINTFLAG(i, epFlags)
@@ -196,6 +196,8 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
196196
}
197197

198198
func initEndpoint(ep, config uint32) {
199+
// Note: Both IN (Bank 1) and OUT (Bank 0) configurations share the same EPCFG register.
200+
// We must use getEPCFG(ep) | ... to avoid clearing/disabling the opposite direction.
199201
switch config {
200202
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
201203
// set packet size
@@ -205,7 +207,7 @@ func initEndpoint(ep, config uint32) {
205207
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
206208

207209
// set endpoint type
208-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
210+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_INTERRUPT+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
209211

210212
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
211213

@@ -217,7 +219,7 @@ func initEndpoint(ep, config uint32) {
217219
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
218220

219221
// set endpoint type
220-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
222+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
221223

222224
// receive interrupts when current transfer complete
223225
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
@@ -236,7 +238,7 @@ func initEndpoint(ep, config uint32) {
236238
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
237239

238240
// set endpoint type
239-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
241+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_INTERRUPT+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
240242

241243
// receive interrupts when current transfer complete
242244
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
@@ -255,7 +257,7 @@ func initEndpoint(ep, config uint32) {
255257
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
256258

257259
// set endpoint type
258-
setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
260+
setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
259261

260262
// NAK on endpoint IN, the bank is not yet filled in.
261263
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
@@ -481,3 +483,19 @@ func setEPINTENCLR(ep uint32, val uint8) {
481483
func setEPINTENSET(ep uint32, val uint8) {
482484
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENSET.Set(val)
483485
}
486+
487+
func (dev *USBDevice) SetStallEPIn(ep uint32) {
488+
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_STALLRQ1)
489+
}
490+
491+
func (dev *USBDevice) SetStallEPOut(ep uint32) {
492+
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_STALLRQ0)
493+
}
494+
495+
func (dev *USBDevice) ClearStallEPIn(ep uint32) {
496+
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ1)
497+
}
498+
499+
func (dev *USBDevice) ClearStallEPOut(ep uint32) {
500+
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ0)
501+
}

src/machine/machine_rp2_usb.go

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,56 @@ var (
2020

2121
func initEndpoint(ep, config uint32) {
2222
val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff)
23+
24+
// Each endpoint has 128 bytes of DPRAM buffer space allocated (2 * usbBufferLen).
25+
// To support bidirectional configurations using the same endpoint number,
26+
// we allocate the first 64 bytes (Buffer0) to OUT transfers, and the remaining
27+
// 64 bytes (Buffer1) to IN transfers by shifting the IN offset by usbBufferLen.
2328
offset := ep*2*usbBufferLen + 0x100
24-
val |= offset
2529

2630
// Bulk and interrupt endpoints must have their Packet ID reset to DATA0 when un-stalled.
27-
epXPIDReset[ep] = false // Default to false in case an endpoint is re-initialized.
31+
// Since both directions share the same ep, we reset their PID flags independently.
32+
if (config & usb.EndpointIn) != 0 {
33+
epXPIDResetIn[ep] = false
34+
} else {
35+
epXPIDResetOut[ep] = false
36+
}
2837

2938
switch config {
3039
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
40+
epXPIDResetIn[ep] = true
41+
epXdata0In[ep] = false
42+
val |= offset + usbBufferLen
3143
val |= usbEpControlEndpointTypeInterrupt
3244
_usbDPSRAM.EPxControl[ep].In.Set(val)
33-
epXPIDReset[ep] = true
3445

3546
case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
47+
epXPIDResetOut[ep] = true
48+
epXdata0Out[ep] = false
49+
val |= offset
3650
val |= usbEpControlEndpointTypeBulk
3751
_usbDPSRAM.EPxControl[ep].Out.Set(val)
3852
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
3953
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
40-
epXPIDReset[ep] = true
4154

4255
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
56+
epXPIDResetOut[ep] = true
57+
epXdata0Out[ep] = false
58+
val |= offset
4359
val |= usbEpControlEndpointTypeInterrupt
4460
_usbDPSRAM.EPxControl[ep].Out.Set(val)
4561
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
4662
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
47-
epXPIDReset[ep] = true
4863

4964
case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
65+
epXPIDResetIn[ep] = true
66+
epXdata0In[ep] = false
67+
val |= offset + usbBufferLen
5068
val |= usbEpControlEndpointTypeBulk
5169
_usbDPSRAM.EPxControl[ep].In.Set(val)
52-
epXPIDReset[ep] = true
5370

5471
case usb.ENDPOINT_TYPE_CONTROL:
72+
val |= offset
5573
val |= usbEpControlEndpointTypeControl
5674
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid)
5775
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
@@ -79,7 +97,7 @@ func sendUSBPacket(ep uint32, data []byte) {
7997
} else {
8098
sendOnEP0DATADONE.offset = 0
8199
}
82-
epXdata0[ep] = true
100+
epXdata0In[ep] = true
83101
}
84102

85103
sendViaEPIn(ep, data, count)
@@ -116,19 +134,29 @@ func handleEndpointRx(ep uint32) []byte {
116134
// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer.
117135
func AckUsbOutTransfer(ep uint32) {
118136
ep = ep & 0x7F
119-
setEPDataPID(ep, !epXdata0[ep])
137+
setEPDataPIDOut(ep, !epXdata0Out[ep])
120138
}
121139

122-
// Set the USB endpoint Packet ID to DATA0 or DATA1.
123-
func setEPDataPID(ep uint32, dataOne bool) {
124-
epXdata0[ep] = dataOne
125-
if epXdata0[ep] || ep == 0 {
140+
// Set the USB endpoint Packet ID to DATA0 or DATA1 for OUT direction.
141+
func setEPDataPIDOut(ep uint32, dataOne bool) {
142+
epXdata0Out[ep] = dataOne
143+
if epXdata0Out[ep] || ep == 0 {
126144
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
127145
}
128146

129147
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
130148
}
131149

150+
// Set the USB endpoint Packet ID to DATA0 or DATA1 for IN direction.
151+
func setEPDataPIDIn(ep uint32, dataOne bool) {
152+
epXdata0In[ep] = dataOne
153+
if epXdata0In[ep] || ep == 0 {
154+
_usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlData1Pid)
155+
}
156+
157+
_usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlAvail)
158+
}
159+
132160
func SendZlp() {
133161
sendUSBPacket(0, nil)
134162
}
@@ -138,15 +166,19 @@ func sendViaEPIn(ep uint32, data []byte, count int) {
138166
val := uint32(count) | usbBuf0CtrlAvail
139167

140168
// DATA0 or DATA1
141-
epXdata0[ep&0x7F] = !epXdata0[ep&0x7F]
142-
if !epXdata0[ep&0x7F] {
169+
epXdata0In[ep&0x7F] = !epXdata0In[ep&0x7F]
170+
if !epXdata0In[ep&0x7F] {
143171
val |= usbBuf0CtrlData1Pid
144172
}
145173

146174
// Mark as full
147175
val |= usbBuf0CtrlFull
148176

149-
copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count])
177+
if (ep & 0x7F) == 0 {
178+
copy(_usbDPSRAM.EPxBuffer[0].Buffer0[:], data[:count])
179+
} else {
180+
copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer1[:], data[:count])
181+
}
150182
_usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
151183
}
152184

@@ -178,9 +210,9 @@ func (dev *USBDevice) ClearStallEPIn(ep uint32) {
178210
ep = ep & 0x7F
179211
val := uint32(usbBuf0CtrlStall)
180212
_usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val)
181-
if epXPIDReset[ep] {
213+
if epXPIDResetIn[ep] {
182214
// Reset the PID to DATA0
183-
setEPDataPID(ep, false)
215+
setEPDataPIDIn(ep, false)
184216
}
185217
}
186218

@@ -189,9 +221,9 @@ func (dev *USBDevice) ClearStallEPOut(ep uint32) {
189221
ep = ep & 0x7F
190222
val := uint32(usbBuf0CtrlStall)
191223
_usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val)
192-
if epXPIDReset[ep] {
224+
if epXPIDResetOut[ep] {
193225
// Reset the PID to DATA0
194-
setEPDataPID(ep, false)
226+
setEPDataPIDOut(ep, false)
195227
}
196228
}
197229

@@ -219,10 +251,12 @@ type usbBuffer struct {
219251
}
220252

221253
var (
222-
_usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
223-
epXdata0 [16]bool
224-
epXPIDReset [16]bool
225-
setupBytes [8]byte
254+
_usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
255+
epXdata0In [16]bool
256+
epXdata0Out [16]bool
257+
epXPIDResetIn [16]bool
258+
epXPIDResetOut [16]bool
259+
setupBytes [8]byte
226260
)
227261

228262
func (d *usbDPSRAM) setupBytes() []byte {

src/machine/usb/cdc/cdc.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
package cdc
44

5+
import (
6+
"machine/usb"
7+
)
8+
59
const (
6-
cdcEndpointACM = 1
7-
cdcEndpointOut = 2
8-
cdcEndpointIn = 3
10+
cdcEndpointACM = usb.CDC_ENDPOINT_ACM
11+
cdcEndpointOut = usb.CDC_ENDPOINT_OUT
12+
cdcEndpointIn = usb.CDC_ENDPOINT_IN
913
)
1014

1115
// New returns USBCDC struct.

src/machine/usb/msc/msc.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ func (m *msc) sendCSW(status csw.Status) {
166166
}
167167
m.cbw.CSW(status, residue, m.cswBuf)
168168
m.state = mscStateStatusSent
169+
m.queuedBytes = csw.MsgLen
169170
m.sendUSBPacket(m.cswBuf)
170171
}
171172

@@ -235,9 +236,9 @@ func (m *msc) run(b []byte, isEpOut bool) bool {
235236
// 6.6.1 CBW Not Valid
236237
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
237238
m.state = mscStateNeedReset
238-
m.stallEndpoint(usb.MSC_ENDPOINT_IN)
239-
m.stallEndpoint(usb.MSC_ENDPOINT_OUT)
240-
m.stallEndpoint(usb.CONTROL_ENDPOINT)
239+
m.stallEndpointIn(usb.MSC_ENDPOINT_IN)
240+
m.stallEndpointOut(usb.MSC_ENDPOINT_OUT)
241+
m.stallEndpointIn(usb.CONTROL_ENDPOINT)
241242
return ack
242243
}
243244

@@ -284,7 +285,7 @@ func (m *msc) run(b []byte, isEpOut bool) bool {
284285
if m.state == mscStateStatus && !m.txStalled {
285286
if m.cbw.transferLength() > m.sentBytes && m.cbw.isIn() {
286287
// 6.7.2 The Thirteen Cases - Case 5 (Hi > Di): STALL before status
287-
m.stallEndpoint(usb.MSC_ENDPOINT_IN)
288+
m.stallEndpointIn(usb.MSC_ENDPOINT_IN)
288289
} else if m.sendZLP {
289290
// Send a zero-length packet to force the end of the transfer before we send a CSW
290291
m.queuedBytes = 0

src/machine/usb/msc/scsi.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCo
298298

299299
if expected > 0 && residue > 0 {
300300
if m.cbw.isIn() {
301-
m.stallEndpoint(usb.MSC_ENDPOINT_IN)
301+
m.stallEndpointIn(usb.MSC_ENDPOINT_IN)
302302
} else {
303-
m.stallEndpoint(usb.MSC_ENDPOINT_OUT)
303+
m.stallEndpointOut(usb.MSC_ENDPOINT_OUT)
304304
}
305305
}
306306
}

0 commit comments

Comments
 (0)