diff --git a/src/machine/machine_atsamd21_usb.go b/src/machine/machine_atsamd21_usb.go index 7ddbd590b1..b68046d484 100644 --- a/src/machine/machine_atsamd21_usb.go +++ b/src/machine/machine_atsamd21_usb.go @@ -334,6 +334,8 @@ func SendUSBInPacket(ep uint32, data []byte) bool { return true } +// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998 +// //go:noinline func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { l := uint16(len(data)) diff --git a/src/machine/machine_atsamd51_usb.go b/src/machine/machine_atsamd51_usb.go index 426c4b53d6..f33f68a938 100644 --- a/src/machine/machine_atsamd51_usb.go +++ b/src/machine/machine_atsamd51_usb.go @@ -337,6 +337,8 @@ func SendUSBInPacket(ep uint32, data []byte) bool { return true } +// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998 +// //go:noinline func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { l := uint16(len(data)) diff --git a/src/machine/machine_nrf52840_usb.go b/src/machine/machine_nrf52840_usb.go index 3dde466367..46d6a66e5f 100644 --- a/src/machine/machine_nrf52840_usb.go +++ b/src/machine/machine_nrf52840_usb.go @@ -252,6 +252,8 @@ func SendUSBInPacket(ep uint32, data []byte) bool { return true } +// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998 +// //go:noinline func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { count := len(data) diff --git a/src/machine/machine_rp2040_usb.go b/src/machine/machine_rp2040_usb.go index d69cd6ad5f..627afd808f 100644 --- a/src/machine/machine_rp2040_usb.go +++ b/src/machine/machine_rp2040_usb.go @@ -6,16 +6,6 @@ import ( "device/rp" "machine/usb" "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -var ( - sendOnEP0DATADONE struct { - offset int - data []byte - pid uint32 - } ) // Configure the USB peripheral. The config is here for compatibility with the UART interface. @@ -134,40 +124,6 @@ func handleUSBIRQ(intr interrupt.Interrupt) { } } -func initEndpoint(ep, config uint32) { - val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff) - offset := ep*2*usbBufferLen + 0x100 - val |= offset - - switch config { - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: - val |= usbEpControlEndpointTypeInterrupt - _usbDPSRAM.EPxControl[ep].In.Set(val) - - 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) - - 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) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: - val |= usbEpControlEndpointTypeBulk - _usbDPSRAM.EPxControl[ep].In.Set(val) - - case usb.ENDPOINT_TYPE_CONTROL: - val |= usbEpControlEndpointTypeControl - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid) - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - - } -} - func handleUSBSetAddress(setup usb.Setup) bool { // Using 570μs timeout which is exactly the same as SAMD21. const ackTimeout = 570 @@ -188,191 +144,6 @@ func handleUSBSetAddress(setup usb.Setup) bool { return true } -// SendUSBInPacket sends a packet for USB (interrupt in / bulk in). -func SendUSBInPacket(ep uint32, data []byte) bool { - sendUSBPacket(ep, data, 0) - return true -} - -//go:noinline -func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { - count := len(data) - if 0 < int(maxsize) && int(maxsize) < count { - count = int(maxsize) - } - - if ep == 0 { - if count > usb.EndpointPacketSize { - count = usb.EndpointPacketSize - - sendOnEP0DATADONE.offset = count - sendOnEP0DATADONE.data = data - } else { - sendOnEP0DATADONE.offset = 0 - } - epXdata0[ep] = true - } - - sendViaEPIn(ep, data, count) -} - -func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { - var b [cdcLineInfoSize]byte - ep := 0 - - for !_usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) { - // TODO: timeout - } - - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - copy(b[:], _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]) - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - - return b, nil -} - -func handleEndpointRx(ep uint32) []byte { - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - return _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz] -} - -func handleEndpointRxComplete(ep uint32) { - epXdata0[ep] = !epXdata0[ep] - if epXdata0[ep] || ep == 0 { - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - } - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) +func armEPZeroStall() { + rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN) } - -func SendZlp() { - sendUSBPacket(0, []byte{}, 0) -} - -func sendViaEPIn(ep uint32, data []byte, count int) { - // Prepare buffer control register value - val := uint32(count) | usbBuf0CtrlAvail - - // DATA0 or DATA1 - epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] - if !epXdata0[ep&0x7F] { - val |= usbBuf0CtrlData1Pid - } - - // Mark as full - val |= usbBuf0CtrlFull - - copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) -} - -func sendStallViaEPIn(ep uint32) { - // Prepare buffer control register value - if ep == 0 { - rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN) - } - val := uint32(usbBuf0CtrlFull) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) - val |= uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) -} - -type usbDPSRAM struct { - // Note that EPxControl[0] is not EP0Control but 8-byte setup data. - EPxControl [16]usbEndpointControlRegister - - EPxBufferControl [16]usbBufferControlRegister - - EPxBuffer [16]usbBuffer -} - -type usbEndpointControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} -type usbBufferControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} - -type usbBuffer struct { - Buffer0 [usbBufferLen]byte - Buffer1 [usbBufferLen]byte -} - -var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - setupBytes [8]byte -) - -func (d *usbDPSRAM) setupBytes() []byte { - - data := d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() - setupBytes[0] = byte(data) - setupBytes[1] = byte(data >> 8) - setupBytes[2] = byte(data >> 16) - setupBytes[3] = byte(data >> 24) - - data = d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() - setupBytes[4] = byte(data) - setupBytes[5] = byte(data >> 8) - setupBytes[6] = byte(data >> 16) - setupBytes[7] = byte(data >> 24) - - return setupBytes[:] -} - -func (d *usbDPSRAM) clear() { - for i := 0; i < len(d.EPxControl); i++ { - d.EPxControl[i].In.Set(0) - d.EPxControl[i].Out.Set(0) - d.EPxBufferControl[i].In.Set(0) - d.EPxBufferControl[i].Out.Set(0) - } -} - -const ( - // DPRAM : Endpoint control register - usbEpControlEnable = 0x80000000 - usbEpControlDoubleBuffered = 0x40000000 - usbEpControlInterruptPerBuff = 0x20000000 - usbEpControlInterruptPerDoubleBuff = 0x10000000 - usbEpControlEndpointType = 0x0c000000 - usbEpControlInterruptOnStall = 0x00020000 - usbEpControlInterruptOnNak = 0x00010000 - usbEpControlBufferAddress = 0x0000ffff - - usbEpControlEndpointTypeControl = 0x00000000 - usbEpControlEndpointTypeISO = 0x04000000 - usbEpControlEndpointTypeBulk = 0x08000000 - usbEpControlEndpointTypeInterrupt = 0x0c000000 - - // Endpoint buffer control bits - usbBuf1CtrlFull = 0x80000000 - usbBuf1CtrlLast = 0x40000000 - usbBuf1CtrlData0Pid = 0x20000000 - usbBuf1CtrlData1Pid = 0x00000000 - usbBuf1CtrlSel = 0x10000000 - usbBuf1CtrlStall = 0x08000000 - usbBuf1CtrlAvail = 0x04000000 - usbBuf1CtrlLenMask = 0x03FF0000 - usbBuf0CtrlFull = 0x00008000 - usbBuf0CtrlLast = 0x00004000 - usbBuf0CtrlData0Pid = 0x00000000 - usbBuf0CtrlData1Pid = 0x00002000 - usbBuf0CtrlSel = 0x00001000 - usbBuf0CtrlStall = 0x00000800 - usbBuf0CtrlAvail = 0x00000400 - usbBuf0CtrlLenMask = 0x000003FF - - usbBufferLen = 64 -) diff --git a/src/machine/machine_rp2350_usb.go b/src/machine/machine_rp2350_usb.go index b42ce09cca..5a298b1afd 100644 --- a/src/machine/machine_rp2350_usb.go +++ b/src/machine/machine_rp2350_usb.go @@ -6,16 +6,6 @@ import ( "device/rp" "machine/usb" "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -var ( - sendOnEP0DATADONE struct { - offset int - data []byte - pid uint32 - } ) // Configure the USB peripheral. The config is here for compatibility with the UART interface. @@ -104,7 +94,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { s2 := rp.USB.BUFF_STATUS.Get() - // OUT (PC -> rp2040) + // OUT (PC -> rp2350) for i := 0; i < 16; i++ { if s2&(1<<(i*2+1)) > 0 { buf := handleEndpointRx(uint32(i)) @@ -115,7 +105,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { } } - // IN (rp2040 -> PC) + // IN (rp2350 -> PC) for i := 0; i < 16; i++ { if s2&(1<<(i*2)) > 0 { if usbTxHandler[i] != nil { @@ -137,44 +127,10 @@ func handleUSBIRQ(intr interrupt.Interrupt) { } } -func initEndpoint(ep, config uint32) { - val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff) - offset := ep*2*usbBufferLen + 0x100 - val |= offset - - switch config { - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: - val |= usbEpControlEndpointTypeInterrupt - _usbDPSRAM.EPxControl[ep].In.Set(val) - - 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) - - 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) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: - val |= usbEpControlEndpointTypeBulk - _usbDPSRAM.EPxControl[ep].In.Set(val) - - case usb.ENDPOINT_TYPE_CONTROL: - val |= usbEpControlEndpointTypeControl - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid) - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - - } -} - func handleUSBSetAddress(setup usb.Setup) bool { // Using 570μs timeout which is exactly the same as SAMD21. - const ackTimeout = 570 + rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_ACK_REC) sendUSBPacket(0, []byte{}, 0) @@ -191,191 +147,6 @@ func handleUSBSetAddress(setup usb.Setup) bool { return true } -// SendUSBInPacket sends a packet for USB (interrupt in / bulk in). -func SendUSBInPacket(ep uint32, data []byte) bool { - sendUSBPacket(ep, data, 0) - return true -} - -//go:noinline -func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { - count := len(data) - if 0 < int(maxsize) && int(maxsize) < count { - count = int(maxsize) - } - - if ep == 0 { - if count > usb.EndpointPacketSize { - count = usb.EndpointPacketSize - - sendOnEP0DATADONE.offset = count - sendOnEP0DATADONE.data = data - } else { - sendOnEP0DATADONE.offset = 0 - } - epXdata0[ep] = true - } - - sendViaEPIn(ep, data, count) -} - -func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { - var b [cdcLineInfoSize]byte - ep := 0 - - for !_usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) { - // TODO: timeout - } - - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - copy(b[:], _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]) - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - - return b, nil +func armEPZeroStall() { + rp.USB.EP_STALL_ARM.Set(rp.USB_EP_STALL_ARM_EP0_IN) } - -func handleEndpointRx(ep uint32) []byte { - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - return _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz] -} - -func handleEndpointRxComplete(ep uint32) { - epXdata0[ep] = !epXdata0[ep] - if epXdata0[ep] || ep == 0 { - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - } - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) -} - -func SendZlp() { - sendUSBPacket(0, []byte{}, 0) -} - -func sendViaEPIn(ep uint32, data []byte, count int) { - // Prepare buffer control register value - val := uint32(count) | usbBuf0CtrlAvail - - // DATA0 or DATA1 - epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] - if !epXdata0[ep&0x7F] { - val |= usbBuf0CtrlData1Pid - } - - // Mark as full - val |= usbBuf0CtrlFull - - copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) -} - -func sendStallViaEPIn(ep uint32) { - // Prepare buffer control register value - if ep == 0 { - rp.USB.EP_STALL_ARM.Set(rp.USB_EP_STALL_ARM_EP0_IN) - } - val := uint32(usbBuf0CtrlFull) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) - val |= uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) -} - -type usbDPSRAM struct { - // Note that EPxControl[0] is not EP0Control but 8-byte setup data. - EPxControl [16]usbEndpointControlRegister - - EPxBufferControl [16]usbBufferControlRegister - - EPxBuffer [16]usbBuffer -} - -type usbEndpointControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} -type usbBufferControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} - -type usbBuffer struct { - Buffer0 [usbBufferLen]byte - Buffer1 [usbBufferLen]byte -} - -var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - setupBytes [8]byte -) - -func (d *usbDPSRAM) setupBytes() []byte { - - data := d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() - setupBytes[0] = byte(data) - setupBytes[1] = byte(data >> 8) - setupBytes[2] = byte(data >> 16) - setupBytes[3] = byte(data >> 24) - - data = d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() - setupBytes[4] = byte(data) - setupBytes[5] = byte(data >> 8) - setupBytes[6] = byte(data >> 16) - setupBytes[7] = byte(data >> 24) - - return setupBytes[:] -} - -func (d *usbDPSRAM) clear() { - for i := 0; i < len(d.EPxControl); i++ { - d.EPxControl[i].In.Set(0) - d.EPxControl[i].Out.Set(0) - d.EPxBufferControl[i].In.Set(0) - d.EPxBufferControl[i].Out.Set(0) - } -} - -const ( - // DPRAM : Endpoint control register - usbEpControlEnable = 0x80000000 - usbEpControlDoubleBuffered = 0x40000000 - usbEpControlInterruptPerBuff = 0x20000000 - usbEpControlInterruptPerDoubleBuff = 0x10000000 - usbEpControlEndpointType = 0x0c000000 - usbEpControlInterruptOnStall = 0x00020000 - usbEpControlInterruptOnNak = 0x00010000 - usbEpControlBufferAddress = 0x0000ffff - - usbEpControlEndpointTypeControl = 0x00000000 - usbEpControlEndpointTypeISO = 0x04000000 - usbEpControlEndpointTypeBulk = 0x08000000 - usbEpControlEndpointTypeInterrupt = 0x0c000000 - - // Endpoint buffer control bits - usbBuf1CtrlFull = 0x80000000 - usbBuf1CtrlLast = 0x40000000 - usbBuf1CtrlData0Pid = 0x20000000 - usbBuf1CtrlData1Pid = 0x00000000 - usbBuf1CtrlSel = 0x10000000 - usbBuf1CtrlStall = 0x08000000 - usbBuf1CtrlAvail = 0x04000000 - usbBuf1CtrlLenMask = 0x03FF0000 - usbBuf0CtrlFull = 0x00008000 - usbBuf0CtrlLast = 0x00004000 - usbBuf0CtrlData0Pid = 0x00000000 - usbBuf0CtrlData1Pid = 0x00002000 - usbBuf0CtrlSel = 0x00001000 - usbBuf0CtrlStall = 0x00000800 - usbBuf0CtrlAvail = 0x00000400 - usbBuf0CtrlLenMask = 0x000003FF - - usbBufferLen = 64 -) diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go new file mode 100644 index 0000000000..414fedb5b6 --- /dev/null +++ b/src/machine/machine_rp2_usb.go @@ -0,0 +1,242 @@ +//go:build rp2040 || rp2350 + +package machine + +import ( + "machine/usb" + "runtime/volatile" + "unsafe" +) + +var ( + sendOnEP0DATADONE struct { + offset int + data []byte + pid uint32 + } +) + +func initEndpoint(ep, config uint32) { + val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff) + offset := ep*2*usbBufferLen + 0x100 + val |= offset + + switch config { + case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: + val |= usbEpControlEndpointTypeInterrupt + _usbDPSRAM.EPxControl[ep].In.Set(val) + + 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) + + 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) + + case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: + val |= usbEpControlEndpointTypeBulk + _usbDPSRAM.EPxControl[ep].In.Set(val) + + case usb.ENDPOINT_TYPE_CONTROL: + val |= usbEpControlEndpointTypeControl + _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid) + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) + + } +} + +// SendUSBInPacket sends a packet for USB (interrupt in / bulk in). +func SendUSBInPacket(ep uint32, data []byte) bool { + sendUSBPacket(ep, data, 0) + return true +} + +// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998 +// +//go:noinline +func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { + count := len(data) + if 0 < int(maxsize) && int(maxsize) < count { + count = int(maxsize) + } + + if ep == 0 { + if count > usb.EndpointPacketSize { + count = usb.EndpointPacketSize + + sendOnEP0DATADONE.offset = count + sendOnEP0DATADONE.data = data + } else { + sendOnEP0DATADONE.offset = 0 + } + epXdata0[ep] = true + } + + sendViaEPIn(ep, data, count) +} + +func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { + var b [cdcLineInfoSize]byte + ep := 0 + + for !_usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) { + // TODO: timeout + } + + ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() + _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) + sz := ctrl & usbBuf0CtrlLenMask + + copy(b[:], _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]) + + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) + + return b, nil +} + +func handleEndpointRx(ep uint32) []byte { + ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() + _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) + sz := ctrl & usbBuf0CtrlLenMask + + return _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz] +} + +func handleEndpointRxComplete(ep uint32) { + epXdata0[ep] = !epXdata0[ep] + if epXdata0[ep] || ep == 0 { + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) + } + + _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) +} + +func SendZlp() { + sendUSBPacket(0, []byte{}, 0) +} + +func sendViaEPIn(ep uint32, data []byte, count int) { + // Prepare buffer control register value + val := uint32(count) | usbBuf0CtrlAvail + + // DATA0 or DATA1 + epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] + if !epXdata0[ep&0x7F] { + val |= usbBuf0CtrlData1Pid + } + + // Mark as full + val |= usbBuf0CtrlFull + + copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) + _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) +} + +func sendStallViaEPIn(ep uint32) { + // Prepare buffer control register value + if ep == 0 { + armEPZeroStall() + } + val := uint32(usbBuf0CtrlFull) + _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) + val |= uint32(usbBuf0CtrlStall) + _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) +} + +type usbDPSRAM struct { + // Note that EPxControl[0] is not EP0Control but 8-byte setup data. + EPxControl [16]usbEndpointControlRegister + + EPxBufferControl [16]usbBufferControlRegister + + EPxBuffer [16]usbBuffer +} + +type usbEndpointControlRegister struct { + In volatile.Register32 + Out volatile.Register32 +} +type usbBufferControlRegister struct { + In volatile.Register32 + Out volatile.Register32 +} + +type usbBuffer struct { + Buffer0 [usbBufferLen]byte + Buffer1 [usbBufferLen]byte +} + +var ( + _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) + epXdata0 [16]bool + setupBytes [8]byte +) + +func (d *usbDPSRAM) setupBytes() []byte { + + data := d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() + setupBytes[0] = byte(data) + setupBytes[1] = byte(data >> 8) + setupBytes[2] = byte(data >> 16) + setupBytes[3] = byte(data >> 24) + + data = d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() + setupBytes[4] = byte(data) + setupBytes[5] = byte(data >> 8) + setupBytes[6] = byte(data >> 16) + setupBytes[7] = byte(data >> 24) + + return setupBytes[:] +} + +func (d *usbDPSRAM) clear() { + for i := 0; i < len(d.EPxControl); i++ { + d.EPxControl[i].In.Set(0) + d.EPxControl[i].Out.Set(0) + d.EPxBufferControl[i].In.Set(0) + d.EPxBufferControl[i].Out.Set(0) + } +} + +const ( + // DPRAM : Endpoint control register + usbEpControlEnable = 0x80000000 + usbEpControlDoubleBuffered = 0x40000000 + usbEpControlInterruptPerBuff = 0x20000000 + usbEpControlInterruptPerDoubleBuff = 0x10000000 + usbEpControlEndpointType = 0x0c000000 + usbEpControlInterruptOnStall = 0x00020000 + usbEpControlInterruptOnNak = 0x00010000 + usbEpControlBufferAddress = 0x0000ffff + + usbEpControlEndpointTypeControl = 0x00000000 + usbEpControlEndpointTypeISO = 0x04000000 + usbEpControlEndpointTypeBulk = 0x08000000 + usbEpControlEndpointTypeInterrupt = 0x0c000000 + + // Endpoint buffer control bits + usbBuf1CtrlFull = 0x80000000 + usbBuf1CtrlLast = 0x40000000 + usbBuf1CtrlData0Pid = 0x20000000 + usbBuf1CtrlData1Pid = 0x00000000 + usbBuf1CtrlSel = 0x10000000 + usbBuf1CtrlStall = 0x08000000 + usbBuf1CtrlAvail = 0x04000000 + usbBuf1CtrlLenMask = 0x03FF0000 + usbBuf0CtrlFull = 0x00008000 + usbBuf0CtrlLast = 0x00004000 + usbBuf0CtrlData0Pid = 0x00000000 + usbBuf0CtrlData1Pid = 0x00002000 + usbBuf0CtrlSel = 0x00001000 + usbBuf0CtrlStall = 0x00000800 + usbBuf0CtrlAvail = 0x00000400 + usbBuf0CtrlLenMask = 0x000003FF + + usbBufferLen = 64 +)