add basic CDC-ACM UART Rx capability

This commit is contained in:
ardnew
2022-02-18 12:09:04 -06:00
committed by sago35
parent 2f50d24fec
commit 5f6489d3cf
5 changed files with 396 additions and 182 deletions
+4 -11
View File
@@ -505,11 +505,10 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// CDC-ACM (single) // CDC-ACM (single)
case classDeviceCDCACM: case classDeviceCDCACM:
// line coding must contain exactly 7 bytes // line coding must contain exactly 7 bytes
if uint16(descCDCACMCodingSize) == sup.wLength { if uint16(descCDCACMLineCodingSize) == sup.wLength {
d.setup = sup
d.controlReceive( d.controlReceive(
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])), uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
uint32(descCDCACMCodingSize), true) uint32(descCDCACMLineCodingSize), true)
// CDC Line Coding packet receipt handling occurs in method // CDC Line Coding packet receipt handling occurs in method
// controlComplete(). // controlComplete().
return dcdStageDataOut return dcdStageDataOut
@@ -534,7 +533,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// Control/status interface: // Control/status interface:
case descCDCACMInterfaceCtrl: case descCDCACMInterfaceCtrl:
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02) // DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
d.uartSetLineState(0 != sup.wValue&0x01, 0 != sup.wValue&0x02) d.uartSetLineState(sup.wValue)
d.controlReceive(uintptr(0), 0, false) d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut return dcdStageStatusOut
@@ -570,7 +569,6 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// HID // HID
case classDeviceHID: case classDeviceHID:
if sup.wLength <= descHIDSxSize { if sup.wLength <= descHIDSxSize {
d.setup = sup
descHID[d.cc.config-1].cx[0] = 0xE9 descHID[d.cc.config-1].cx[0] = 0xE9
d.controlReceive( d.controlReceive(
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])), uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
@@ -687,12 +685,7 @@ func (d *dcd) controlComplete() {
case descCDCACMInterfaceCtrl: case descCDCACMInterfaceCtrl:
// Notify PHY to handle triggers like special baud rates, which // Notify PHY to handle triggers like special baud rates, which
// signal to reboot into bootloader or begin receiving OTA updates // signal to reboot into bootloader or begin receiving OTA updates
d.uartSetLineCoding(descCDCACMLineCoding{ d.uartSetLineCoding(acm.cx[:])
baud: packU32(acm.cx[:]),
stopBits: acm.cx[4],
parity: acm.cx[5],
numBits: acm.cx[6],
})
default: default:
// Unhandled device interface // Unhandled device interface
+45 -7
View File
@@ -1,7 +1,5 @@
package usb package usb
import "unsafe"
const descUSBSpecVersion = uint16(0x0200) // USB 2.0 const descUSBSpecVersion = uint16(0x0200) // USB 2.0
const descLanguageEnglish = uint16(0x0409) // (US) English const descLanguageEnglish = uint16(0x0409) // (US) English
@@ -140,6 +138,9 @@ const (
const ( const (
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
descDirRx = descDirOut // "IN" and "OUT" terms are from host's perspective,
descDirTx = descDirIn // which is opposite from USB device. Kinda awkward.
) )
// device returns the enumerated device descriptor value, defined per USB // device returns the enumerated device descriptor value, defined per USB
@@ -429,15 +430,55 @@ const (
// descEndpointInvalid represents an invalid endpoint address. // descEndpointInvalid represents an invalid endpoint address.
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk) const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer. // descCDCACMLineCodingSize defines the length of a CDC-ACM UART line coding
const descCDCACMCodingSize = unsafe.Sizeof(descCDCACMLineCoding{}) // buffer. Note that the actual buffer may be padded for alignment; but for
// Rx/Tx transfer purposes, descCDCACMLineCodingSize defines the number of bytes
// that are transferred following a control SETUP request.
const descCDCACMLineCodingSize = 7
// descCDCACMLineCoding represents an emulated UART's line configuration. // descCDCACMLineCoding represents an emulated UART's line configuration.
//
// Use descCDCACMLineCodingSize instead of unsafe.Sizeof(descCDCACMLineCoding)
// in any transfer requests, because the actual struct is padded for alignment.
type descCDCACMLineCoding struct { type descCDCACMLineCoding struct {
baud uint32 baud uint32
stopBits uint8 stopBits uint8
parity uint8 parity uint8
numBits uint8 numBits uint8
_ uint8
}
// parse initializes the receiver descCDCACMLineCoding from the given []uint8 v.
// Argument v is a Rx transfer buffer, filled following the completion of a
// control transfer from a CDC SET_LINE_CODING (0x20) request
func (s *descCDCACMLineCoding) parse(v []uint8) bool {
if len(v) >= descCDCACMLineCodingSize {
s.baud = packU32(v[:])
s.stopBits = v[4]
s.parity = v[5]
s.numBits = v[6]
return true
}
return false
}
// descCDCACMLineState represents an emulated UART's line state.
type descCDCACMLineState struct {
// dataTerminalReady indicates if DTE is present or not.
// Corresponds to V.24 signal 108/2 and RS-232 signal DTR.
dataTerminalReady bool // DTR
// requestToSend is the carrier control for half-duplex modems.
// Corresponds to V.24 signal 105 and RS-232 signal RTS.
requestToSend bool // RTS
}
// parse initializes the receiver descCDCACMLineState from the given uint16 v.
// Argument v corresponds to the wValue field in a control SETUP packet, which
// carries the line state from a CDC SET_CONTROL_LINE_STATE (0x22) request.
func (s *descCDCACMLineState) parse(v uint16) bool {
s.dataTerminalReady = 0 != v&0x1
s.requestToSend = 0 != v&0x2
return true
} }
// Common configuration constants for the USB CDC-ACM (single) device class. // Common configuration constants for the USB CDC-ACM (single) device class.
@@ -465,9 +506,6 @@ const (
type descCDCACMClass struct { type descCDCACMClass struct {
*descCDCACMClassData // Target-defined, class-specific data *descCDCACMClassData // Target-defined, class-specific data
line descCDCACMLineCoding
term struct{ dtr, rts bool }
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
device *[descLengthDevice]uint8 // device descriptor device *[descLengthDevice]uint8 // device descriptor
qualif *[descLengthQualification]uint8 // device qualification descriptor qualif *[descLengthQualification]uint8 // device qualification descriptor
+27 -8
View File
@@ -38,9 +38,6 @@ const (
descMaxEndpoints = 8 // SAMx51 maximum number of endpoints descMaxEndpoints = 8 // SAMx51 maximum number of endpoints
descBankOut = 0 // descriptor bank 0 holds OUT endpoints
descBankIn = 1 // descriptor bank 1 holds IN endpoints
descControlPacketSize = 64 descControlPacketSize = 64
) )
@@ -69,8 +66,8 @@ const (
// CDC-ACM Data Buffers // CDC-ACM Data Buffers
descCDCACMRxSize = 4 * descCDCACMDataRxPacketSize descCDCACMRxSize = 1 * descCDCACMDataRxPacketSize
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize descCDCACMTxSize = 1 * descCDCACMDataTxPacketSize
descCDCACMTxTimeoutMs = 120 // millisec descCDCACMTxTimeoutMs = 120 // millisec
descCDCACMTxSyncUs = 75 // microsec descCDCACMTxSyncUs = 75 // microsec
@@ -221,6 +218,16 @@ var descCDCACM0Rx [descCDCACMRxSize]uint8
//go:align 32 //go:align 32
var descCDCACM0Tx [descCDCACMTxSize]uint8 var descCDCACM0Tx [descCDCACMTxSize]uint8
// descCDCACM0LC is the emulated UART's line coding configuration for the
// default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDCACM0LC descCDCACMLineCoding
// descCDCACM0LS is the emulated UART's line state for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDCACM0LS descCDCACMLineState
// descCDCACMClassData holds the buffers and control states for all CDC-ACM // descCDCACMClassData holds the buffers and control states for all CDC-ACM
// (single) device class configurations, ordered by index (offset by -1), for // (single) device class configurations, ordered by index (offset by -1), for
// SAMx51 targets only. // SAMx51 targets only.
@@ -245,9 +252,15 @@ type descCDCACMClassData struct {
rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
sxSize uint16 lc *descCDCACMLineCoding // UART line coding
rxSize uint16 ls *descCDCACMLineState // UART line state
txSize uint16
rq *Queue
tq *Queue
sxSize uint32
rxSize uint32
txSize uint32
} }
// descCDCACMData holds statically-allocated instances for each of the target- // descCDCACMData holds statically-allocated instances for each of the target-
@@ -271,6 +284,12 @@ var descCDCACMData = [dcdCount]descCDCACMClassData{
rx: &descCDCACM0Rx, rx: &descCDCACM0Rx,
tx: &descCDCACM0Tx, tx: &descCDCACM0Tx,
lc: &descCDCACM0LC,
ls: &descCDCACM0LS,
rq: &Queue{},
tq: &Queue{},
sxSize: descCDCACMStatusPacketSize, sxSize: descCDCACMStatusPacketSize,
rxSize: descCDCACMDataRxPacketSize, rxSize: descCDCACMDataRxPacketSize,
txSize: descCDCACMDataTxPacketSize, txSize: descCDCACMDataTxPacketSize,
+108 -102
View File
@@ -9,6 +9,7 @@ package usb
import ( import (
"device/arm" "device/arm"
"device/sam" "device/sam"
"math/bits"
"runtime/interrupt" "runtime/interrupt"
"runtime/volatile" "runtime/volatile"
"unsafe" "unsafe"
@@ -34,31 +35,11 @@ type dhw struct {
ep [descMaxEndpoints]dhwEPAddrStatus ep [descMaxEndpoints]dhwEPAddrStatus
log [2048][64]byte
logCount uint
setup dcdSetup setup dcdSetup
stage dcdStage stage dcdStage
address uint16 address uint16
} }
var a uint
func (d *dhw) logEvent(s string) {
d.enableInterrupts(false)
copy(d.log[d.logCount][:], s)
d.logCount++
if d.logCount > 20 {
d.logReset()
}
d.enableInterrupts(true)
}
//go:noinline
func (d *dhw) logReset() {
a = d.logCount
}
func deleteCache(addr, size uintptr) {} func deleteCache(addr, size uintptr) {}
func flushCache(addr, size uintptr) {} func flushCache(addr, size uintptr) {}
func runBootloader() {} func runBootloader() {}
@@ -86,20 +67,12 @@ func allocDHW(port, instance int, speed Speed, dc *dcd) *dhw {
} }
// SAMx51 has only one USB PHY, which is full-speed // SAMx51 has only one USB PHY, which is full-speed
if 0 == speed { if speed == 0 {
speed = FullSpeed speed = FullSpeed
} }
dhwInstance[instance].speed = speed dhwInstance[instance].speed = speed
dhwInstance[instance].ready = false dhwInstance[instance].ready = false
// initialize the transfer descriptors
for i := range dhwInstance[instance].ep {
dhwInstance[instance].ep[i][descBankOut].init(
&dhwInstance[instance], rxEndpoint(uint8(i)))
dhwInstance[instance].ep[i][descBankIn].init(
&dhwInstance[instance], txEndpoint(uint8(i)))
}
return &dhwInstance[instance] return &dhwInstance[instance]
} }
@@ -327,12 +300,12 @@ func (d *dhw) interrupt() {
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP | sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP |
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
d.logEvent("setup received")
// Parse the SETUP packet immediately, clearing room in the (one and only) // Parse the SETUP packet immediately, clearing room in the (one and only)
// control buffer for the next SETUP packet received. // control buffer for the next SETUP packet received.
sup := setupFrom(d.controlSetupBuffer()) sup := setupFrom(d.controlSetupBuffer())
dir := sup.direction() dir := sup.direction()
// We've copied the SETUP packet elsewhere and are ready to receive another.
d.prepareSetup() d.prepareSetup()
// Although there is only one control buffer, EP0 has two transfer queues: // Although there is only one control buffer, EP0 has two transfer queues:
@@ -350,14 +323,12 @@ func (d *dhw) interrupt() {
} }
} }
// maybe transfer complete epints := d.bus.EPINTSMRY.Get() & ((1 << descMaxEndpoints) - 1)
epints := d.bus.EPINTSMRY.Get() for epints != 0 {
for ep := uint8(0); ep < descMaxEndpoints; ep++ { ep := uint8(bits.TrailingZeros16(epints))
if (epints & (1 << ep)) == 0 { epints &^= 1 << ep
continue
}
intFlag := d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Get() intFlag := d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
@@ -378,22 +349,20 @@ func (d *dhw) interrupt() {
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set( d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
d.controlStall(false, descDirIn)
if ep == d.controlEndpoint() { if ep == d.controlEndpoint() {
d.logEvent("EP0 Tx packet complete") d.controlStall(false, descDirTx)
// check if there is more data to transfer or if we need to notify the // check if there is more data to transfer or if we need to notify the
// upper-layer device driver of a control transfer completion event. // upper-layer device driver of a control transfer completion event.
if count == 0 || count < size { if count == 0 || count < size {
d.logEvent("EP0 Tx transfer complete")
d.controlTransferComplete(txEndpoint(ep), count, total) d.controlTransferComplete(txEndpoint(ep), count, total)
} else { } else {
d.controlTransferContinue(txEndpoint(ep), count, total) d.controlTransferContinue(txEndpoint(ep), count, total)
} }
} else if nil != d.ep[ep][descBankIn].callback { } else if nil != d.ep[ep][descDirTx].callback {
// call our device class-specific callback, if defined, on endpoint // call our device class-specific callback, if defined, on endpoint
// data transfer complete events. // data transfer complete events.
d.ep[ep][descBankIn].callback(txEndpoint(ep), count) d.ep[ep][descDirTx].callback(txEndpoint(ep), count)
} }
} }
@@ -412,22 +381,20 @@ func (d *dhw) interrupt() {
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set( d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
d.controlStall(false, descDirOut)
if ep == d.controlEndpoint() { if ep == d.controlEndpoint() {
d.logEvent("EP0 Rx packet complete") d.controlStall(false, descDirRx)
// check if there is more data to transfer or if we need to notify the // check if there is more data to transfer or if we need to notify the
// upper-layer device driver of a control transfer completion event. // upper-layer device driver of a control transfer completion event.
if count == 0 || count < size { if count == 0 || count < size {
d.logEvent("EP0 Rx transfer complete")
d.controlTransferComplete(rxEndpoint(ep), count, total) d.controlTransferComplete(rxEndpoint(ep), count, total)
} else { } else {
d.controlTransferContinue(rxEndpoint(ep), count, total) d.controlTransferContinue(rxEndpoint(ep), count, total)
} }
} else if nil != d.ep[ep][descBankOut].callback { } else if nil != d.ep[ep][descDirRx].callback {
// call our device class-specific callback, if defined, on endpoint // call our device class-specific callback, if defined, on endpoint
// data transfer complete events. // data transfer complete events.
d.ep[ep][descBankOut].callback(rxEndpoint(ep), count) d.ep[ep][descDirRx].callback(rxEndpoint(ep), count)
} }
} }
} }
@@ -532,10 +499,11 @@ func (d *dhw) controlStatusStart(endpoint uint8) {
num, dir := unpackEndpoint(endpoint) num, dir := unpackEndpoint(endpoint)
// Swap direction of the given endpoint Rx->Tx and Tx->Rx
switch dir { switch dir {
case descDirOut: case descDirRx:
endpoint = txEndpoint(num) endpoint = txEndpoint(num)
case descDirIn: case descDirTx:
endpoint = rxEndpoint(num) endpoint = rxEndpoint(num)
} }
d.endpointTransfer(endpoint, 0, 0) d.endpointTransfer(endpoint, 0, 0)
@@ -543,8 +511,6 @@ func (d *dhw) controlStatusStart(endpoint uint8) {
func (d *dhw) controlStatusComplete(endpoint uint8) { func (d *dhw) controlStatusComplete(endpoint uint8) {
d.logEvent("setup processing complete")
if (d.setup.bmRequestType&descRequestTypeTypeMsk == descRequestTypeTypeStandard) && if (d.setup.bmRequestType&descRequestTypeTypeMsk == descRequestTypeTypeStandard) &&
(d.setup.bmRequestType&(descRequestTypeRecipientMsk|descRequestTypeDirMsk) == (d.setup.bmRequestType&(descRequestTypeRecipientMsk|descRequestTypeDirMsk) ==
descRequestTypeRecipientDevice|descRequestTypeDirOut) && descRequestTypeRecipientDevice|descRequestTypeDirOut) &&
@@ -564,7 +530,6 @@ func (d *dhw) controlTransferStart(endpoint uint8) {
// Dequeue the next transfer descriptor available. // Dequeue the next transfer descriptor available.
if xfer, ok := d.ep[num][dir].pendingTransfer(); ok { if xfer, ok := d.ep[num][dir].pendingTransfer(); ok {
d.logEvent("setup processing begin")
// Update the active transfer descriptor on the corresponding endpoint. // Update the active transfer descriptor on the corresponding endpoint.
d.ep[num][dir].setActiveTransfer(xfer) d.ep[num][dir].setActiveTransfer(xfer)
// Invoke the DCD event handler for SETUP processing, which will enqueue // Invoke the DCD event handler for SETUP processing, which will enqueue
@@ -593,8 +558,6 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
setupDir := d.setup.direction() setupDir := d.setup.direction()
setupAddress := packEndpoint(num, setupDir) setupAddress := packEndpoint(num, setupDir)
d.logEvent("setup packet complete")
// If endpoint direction is opposite the direction in the original SETUP // If endpoint direction is opposite the direction in the original SETUP
// packet, then this is the end of the STATUS stage, i.e., end of transfer. // packet, then this is the end of the STATUS stage, i.e., end of transfer.
if dir != setupDir { if dir != setupDir {
@@ -607,7 +570,6 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
// Start processing any pending control transfers. // Start processing any pending control transfers.
d.controlTransferStart(setupAddress) d.controlTransferStart(setupAddress)
} else { } else {
d.logEvent("control status phase")
// Initiate ZLP transfer in opposite direction. // Initiate ZLP transfer in opposite direction.
d.controlStatusStart(endpoint) d.controlStatusStart(endpoint)
} }
@@ -619,7 +581,7 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) { func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) {
ep := d.controlEndpoint() ep := d.controlEndpoint()
if size > 0 && data > 0 { if size > 0 && data > 0 {
if xfer, ok := d.ep[ep][descBankOut].activeTransfer(); ok { if xfer, ok := d.ep[ep][descDirRx].activeTransfer(); ok {
next := xfer.packetStart(data, size) next := xfer.packetStart(data, size)
d.endpointTransfer(rxEndpoint(ep), data, next) d.endpointTransfer(rxEndpoint(ep), data, next)
} }
@@ -634,7 +596,7 @@ func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) {
func (d *dhw) controlTransmit(data uintptr, size uint32, notify bool) { func (d *dhw) controlTransmit(data uintptr, size uint32, notify bool) {
ep := d.controlEndpoint() ep := d.controlEndpoint()
if size > 0 && data > 0 { if size > 0 && data > 0 {
if xfer, ok := d.ep[ep][descBankIn].activeTransfer(); ok { if xfer, ok := d.ep[ep][descDirTx].activeTransfer(); ok {
next := xfer.packetStart(data, size) next := xfer.packetStart(data, size)
d.endpointTransfer(txEndpoint(ep), data, next) d.endpointTransfer(txEndpoint(ep), data, next)
} }
@@ -658,9 +620,9 @@ type dhwTransfer struct {
// dhwTransferDepth defines the size of the dhwEPStatus.xferQueue buffered channel, // dhwTransferDepth defines the size of the dhwEPStatus.xferQueue buffered channel,
// which affects the number of transfers each endpoint can enqueue for processing. // which affects the number of transfers each endpoint can enqueue for processing.
// const dhwTransferDepth = 8 const dhwTransferDepth = 8
type dhwTransferLUT [QueueSize]dhwTransfer type dhwTransferLUT [dhwTransferDepth]dhwTransfer
func (t *dhwTransfer) init(endpoint uint8, maxPacketSize uint32) { func (t *dhwTransfer) init(endpoint uint8, maxPacketSize uint32) {
t.endpoint = endpoint t.endpoint = endpoint
@@ -741,6 +703,7 @@ type dhwEPStatus struct {
callback func(endpoint uint8, size uint32) callback func(endpoint uint8, size uint32)
flags volatile.Register8 flags volatile.Register8
xferActive volatile.Register32 xferActive volatile.Register32
xferFIFO [dhwTransferDepth]uint8
xferQueue Queue xferQueue Queue
xferTable dhwTransferLUT xferTable dhwTransferLUT
} }
@@ -761,7 +724,8 @@ func (s *dhwEPStatus) init(dhw *dhw, endpoint uint8) {
s.endpoint = endpoint s.endpoint = endpoint
s.callback = nil s.callback = nil
s.flags.Set(0) s.flags.Set(0)
s.xferQueue.Reset() fifo := s.xferFIFO[:]
s.xferQueue.Init(&fifo, dhwTransferDepth, QueueFullDiscardLast)
mps := dhw.endpointMaxPacketSize(endpoint) mps := dhw.endpointMaxPacketSize(endpoint)
for i := range s.xferTable { for i := range s.xferTable {
s.xferTable[i].init(endpoint, mps) s.xferTable[i].init(endpoint, mps)
@@ -955,7 +919,6 @@ func (s *dhwEPStatus) scheduleTransfer(data uintptr, size uint32) (ready bool, o
// returned for both return values. // returned for both return values.
func (s *dhwEPStatus) scheduleSetup(setup dcdSetup) (ready bool, ok bool) { func (s *dhwEPStatus) scheduleSetup(setup dcdSetup) (ready bool, ok bool) {
var i int var i int
s.device.logEvent("setup queued")
if i, ok = s.claimSchedule(); ok { if i, ok = s.claimSchedule(); ok {
defer s.device.enableInterrupts(true) defer s.device.enableInterrupts(true)
s.xferTable[i].reset() s.xferTable[i].reset()
@@ -1157,14 +1120,18 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
if enum, ok := endpointSizeEncode(descControlPacketSize); ok { if enum, ok := endpointSizeEncode(descControlPacketSize); ok {
num := endpointNumber(d.controlEndpoint())
// Initialize IN and OUT transfer descriptors on control endpoint 0.
d.ep[num][descDirRx].init(d, rxEndpoint(num))
d.ep[num][descDirTx].init(d, txEndpoint(num))
// Conigure packet size for control endpoints. // Conigure packet size for control endpoints.
out.packetSize.ReplaceBits(enum, out.packetSize.ReplaceBits(enum,
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos) USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
in.packetSize.ReplaceBits(enum, in.packetSize.ReplaceBits(enum,
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos) USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
num := endpointNumber(d.controlEndpoint())
// rxType/txType uses the same rationale as epType (defined below in the // rxType/txType uses the same rationale as epType (defined below in the
// else-branch that handles non-control endpoints). // else-branch that handles non-control endpoints).
// Thus, we add +1 to the value below. // Thus, we add +1 to the value below.
@@ -1193,11 +1160,15 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
if enum, ok := endpointSizeEncode(d.endpointMaxPacketSize(endpoint)); ok { if enum, ok := endpointSizeEncode(d.endpointMaxPacketSize(endpoint)); ok {
num, dir := unpackEndpoint(endpoint)
// Initialize transfer descriptors now that the device class configuration
// has been defined, which affects maximum packet size.
d.ep[num][dir].init(d, endpoint)
desc.packetSize.ReplaceBits(enum, desc.packetSize.ReplaceBits(enum,
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos) USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
num := endpointNumber(endpoint)
// config contains the bmAttributes field per USB standard EP descriptor, // config contains the bmAttributes field per USB standard EP descriptor,
// i.e., ctrl=0, iso=1, bulk=2, int=3, which corresponds to the EPCFG // i.e., ctrl=0, iso=1, bulk=2, int=3, which corresponds to the EPCFG
// register's EPTYPE0/1 bitfield+1: ctrl=1, iso=2, bulk=3, int=4, dual=5. // register's EPTYPE0/1 bitfield+1: ctrl=1, iso=2, bulk=3, int=4, dual=5.
@@ -1217,9 +1188,8 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ0 | sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ0 |
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLOUT) sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLOUT)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits( d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0_Msk, 0)
case txEndpoint(endpoint): case txEndpoint(endpoint):
@@ -1234,15 +1204,16 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ1 | sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ1 |
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLIN) sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLIN)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits( d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1_Msk, 0)
} }
} }
} }
} }
func (d *dhw) endpointConfigure(endpoint uint8) { func (d *dhw) endpointConfigure(endpoint uint8, callback func(endpoint uint8, size uint32)) {
num, dir := unpackEndpoint(endpoint)
d.ep[num][dir].callback = callback
} }
// endpointStall sets or clears a stall on the given endpoint. // endpointStall sets or clears a stall on the given endpoint.
@@ -1299,7 +1270,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
switch num, dir := unpackEndpoint(endpoint); dir { switch num, dir := unpackEndpoint(endpoint); dir {
case descDirOut: // Rx case descDirRx: // OUT
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with 0 and // overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with 0 and
// size, respectively). // size, respectively).
@@ -1315,7 +1286,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
d.bus.DEVICE_ENDPOINT[num].EPINTFLAG.SetBits( d.bus.DEVICE_ENDPOINT[num].EPINTFLAG.SetBits(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRFAIL0) sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRFAIL0)
case descDirIn: // Tx case descDirTx: // IN
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with size // overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with size
// and 0, respectively). // and 0, respectively).
@@ -1364,54 +1335,89 @@ func (d *dhw) uartConfigure() {
acm := &descCDCACM[d.cc.config-1] acm := &descCDCACM[d.cc.config-1]
// SAMx51 only supports USB full-speed (FS) operation // SAMx51 only supports USB full-speed (FS) operation
acm.sxSize = descCDCACMStatusFSPacketSize
acm.rxSize = descCDCACMDataRxFSPacketSize acm.rxSize = descCDCACMDataRxFSPacketSize
acm.txSize = descCDCACMDataTxFSPacketSize acm.txSize = descCDCACMDataTxFSPacketSize
d.endpointEnable(descCDCACMEndpointStatus, rq := acm.rx[:]
tq := acm.tx[:]
// Rx gives priority to incoming data, Tx gives priority to outgoing data
acm.rq.Init(&rq, descCDCACMRxSize, QueueFullDiscardFirst)
acm.tq.Init(&tq, descCDCACMTxSize, QueueFullDiscardLast)
d.endpointEnable(txEndpoint(descCDCACMEndpointStatus),
false, descCDCACMConfigAttrStatus) false, descCDCACMConfigAttrStatus)
d.endpointEnable(descCDCACMEndpointDataRx, d.endpointEnable(rxEndpoint(descCDCACMEndpointDataRx),
false, descCDCACMConfigAttrDataRx) false, descCDCACMConfigAttrDataRx)
d.endpointEnable(descCDCACMEndpointDataTx, d.endpointEnable(txEndpoint(descCDCACMEndpointDataTx),
false, descCDCACMConfigAttrDataTx) false, descCDCACMConfigAttrDataTx)
/*
d.endpointConfigureTx(descCDCACMEndpointStatus,
acm.sxSize, false, nil)
d.endpointConfigureRx(descCDCACMEndpointDataRx,
acm.rxSize, false, d.uartNotify)
d.endpointConfigureTx(descCDCACMEndpointDataTx,
acm.txSize, true, nil)
for i := range acm.rd { d.endpointConfigure(txEndpoint(descCDCACMEndpointStatus),
d.uartReceive(uint8(i)) nil)
d.endpointConfigure(rxEndpoint(descCDCACMEndpointDataRx),
d.uartReceiveComplete)
d.endpointConfigure(txEndpoint(descCDCACMEndpointDataTx),
nil)
d.uartReceive(descCDCACMEndpointDataRx)
}
func (d *dhw) uartSetLineState(state uint16) {
acm := &descCDCACM[d.cc.config-1]
if acm.ls.parse(state) {
// TBD: respond to changes in line state?
}
}
func (d *dhw) uartSetLineCoding(coding []uint8) {
acm := &descCDCACM[d.cc.config-1]
if acm.lc.parse(coding) {
switch acm.lc.baud {
case 1200:
if acm.ls.dataTerminalReady {
// reboot CPU
}
} }
*/
d.timerConfigure(0, descCDCACMTxSyncUs, d.uartSync)
}
func (d *dhw) uartSetLineState(dtr, rts bool) {
}
func (d *dhw) uartSetLineCoding(coding descCDCACMLineCoding) {
if 134 == coding.baud {
d.enableSOF(true, descCDCACMInterfaceCount)
} }
} }
func (d *dhw) uartReady() bool { func (d *dhw) uartReady() bool {
acm := &descCDCACM[d.cc.config-1] return d.dcd.state() == dcdStateConfigured
_ = acm // TODO(ardnew): elaborate stub
return false
} }
func (d *dhw) uartReceive(endpoint uint8) { func (d *dhw) uartReceive(endpoint uint8) {
acm := &descCDCACM[d.cc.config-1] acm := &descCDCACM[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk num := uint16(endpoint) & descEndptAddrNumberMsk
_, _ = acm, num // TODO(ardnew): elaborate stub
ready, _ := d.ep[num][descDirRx].scheduleTransfer(
uintptr(unsafe.Pointer(&acm.rx[0])), acm.rxSize)
if ready {
if xfer, ok := d.ep[num][descDirRx].pendingTransfer(); ok {
// Update the active transfer descriptor on the corresponding endpoint.
d.ep[num][descDirRx].setActiveTransfer(xfer)
next := xfer.packetStart(xfer.data, xfer.size)
d.endpointTransfer(endpoint, xfer.data, next)
}
}
} }
func (d *dhw) uartNotify(endpoint uint8, size uint32) { func (d *dhw) uartReceiveComplete(endpoint uint8, size uint32) {
acm := &descCDCACM[d.cc.config-1] acm := &descCDCACM[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
_ = acm // TODO(ardnew): elaborate stub _ = acm // TODO(ardnew): elaborate stub
if xfer, ok := d.ep[num][descDirRx].activeTransfer(); ok {
for ptr := xfer.data + uintptr(xfer.sent); ptr < xfer.data+uintptr(size); ptr++ {
acm.rq.Enq(*(*uint8)(unsafe.Pointer(ptr)))
}
if data, size := xfer.packetComplete(size); size > 0 {
d.endpointTransfer(endpoint, data, size)
return
}
}
d.ep[num][descDirRx].setActiveTransfer(nil)
d.uartReceive(endpoint)
} }
// uartFlush discards all buffered input (Rx) data. // uartFlush discards all buffered input (Rx) data.
@@ -1445,7 +1451,7 @@ func (d *dhw) uartRead(data []uint8) int {
} }
func (d *dhw) uartWriteByte(c uint8) bool { func (d *dhw) uartWriteByte(c uint8) bool {
return 1 == d.uartWrite([]uint8{c}) return d.uartWrite([]uint8{c}) == 1
} }
func (d *dhw) uartWrite(data []uint8) int { func (d *dhw) uartWrite(data []uint8) int {
+212 -54
View File
@@ -5,12 +5,19 @@ import (
"runtime/volatile" "runtime/volatile"
) )
const QueueSize = 8 type QueueFullDiscardMode uint8
const (
QueueFullDiscardLast QueueFullDiscardMode = iota // Drop incoming data
QueueFullDiscardFirst // Drop outgoing data
)
type Queue struct { type Queue struct {
fifo [QueueSize]uint8 mode QueueFullDiscardMode
tail volatile.Register32 size volatile.Register32
head volatile.Register32 fifo *[]uint8
tail volatile.Register32 // New elements are enqueued at index tail
head volatile.Register32 // Oldest element in queue is at index head
} }
var ( var (
@@ -18,28 +25,94 @@ var (
ErrWriteBuffer = errors.New("cannot copy from write buffer") ErrWriteBuffer = errors.New("cannot copy from write buffer")
ErrQueueEmpty = errors.New("data queue empty") // Read Error ErrQueueEmpty = errors.New("data queue empty") // Read Error
ErrQueueFull = errors.New("data queue full") // Write error ErrQueueFull = errors.New("data queue full") // Write error
ErrQueueNoMode = errors.New("unknown FIFO copy mode")
) )
// Reset discards all buffered data. // Init initializes the receiver queue's backing data store with the given byte
// slice fifo and logical capacity size. If size is greater than the slice's
// physical length, uses the slice's physical length.
func (q *Queue) Init(fifo *[]uint8, size int, mode QueueFullDiscardMode) {
q.mode = mode
q.fifo = fifo
q.Reset(size)
}
// Reset discards all buffered data and sets the FIFO logical capacity.
// If size is less than 0 or greater than FIFO physical length, uses FIFO
// physical length.
//go:inline //go:inline
func (q *Queue) Reset() { func (q *Queue) Reset(size int) {
for i := range q.fifo { if phy := len(*q.fifo); size < 0 || size > phy {
q.fifo[i] = 0 size = phy
} }
q.size.Set(uint32(size))
q.tail.Set(0) q.tail.Set(0)
q.head.Set(0) q.head.Set(0)
} }
// Cap returns the logical capacity of the receiver FIFO.
//go:inline
func (q *Queue) Cap() int {
return int(q.size.Get())
}
// Len returns the number of elements enqueued in the receiver FIFO.
//go:inline //go:inline
func (q *Queue) Len() int { func (q *Queue) Len() int {
return int(q.tail.Get() - q.head.Get()) return int(q.tail.Get() - q.head.Get())
} }
// Rem returns the number of elements not enqueued in the receiver FIFO.
//go:inline //go:inline
func (q *Queue) Cap() int { func (q *Queue) Rem() int {
return cap(q.fifo) return q.Cap() - q.Len()
} }
// Deq dequeues and returns the element at the front of the receiver FIFO and true.
// If the FIFO is empty and no element was dequeued, returns 0 and false.
func (q *Queue) Deq() (uint8, bool) {
head := q.head.Get()
if head == q.tail.Get() {
return 0, false
} // empty queue
data := (*q.fifo)[head%q.size.Get()]
q.head.Set(head + 1)
return data, true
}
// Enq enqueues the given element data at the back of the receiver FIFO and
// returns true.
// If the FIFO is full and no element can be enqueued, returns false.
//
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
func (q *Queue) Enq(data uint8) bool {
tail := q.tail.Get()
head := q.head.Get()
if tail-head == q.size.Get() {
switch q.mode {
case QueueFullDiscardLast:
// drop incoming data
return false
case QueueFullDiscardFirst:
// drop outgoing data
q.head.Set(head + 1)
}
} // full queue
(*q.fifo)[tail%q.size.Get()] = data
q.tail.Set(tail + 1)
return true
}
// Read implements the io.Reader interface. It dequeues min(q.Len(), len(data))
// elements from the receiver FIFO into the given slice data.
// If len(data) equals 0, returns 0 and ErrReadBuffer.
// Otherwise, if q.Len() equals 0, returns 0 and ErrQueueEmpty.
func (q *Queue) Read(data []uint8) (int, error) { func (q *Queue) Read(data []uint8) (int, error) {
less := uint32(len(data)) less := uint32(len(data))
@@ -59,7 +132,7 @@ func (q *Queue) Read(data []uint8) (int, error) {
} // only get from used space } // only get from used space
for i := uint32(0); i < less; i++ { for i := uint32(0); i < less; i++ {
data[i] = q.fifo[head%QueueSize] data[i] = (*q.fifo)[head%q.size.Get()]
head++ head++
} }
q.head.Set(head) q.head.Set(head)
@@ -67,65 +140,150 @@ func (q *Queue) Read(data []uint8) (int, error) {
return int(less), nil return int(less), nil
} }
// Write implements the io.Writer interface. It enqueues min(q.Rem(), len(data))
// elements from the given slice data into the receiver FIFO.
// If len(data) equals 0, returns 0 and ErrWriteBuffer.
// Otherwise, if q.Rem() equals 0, returns 0 and ErrQueueFull.
//
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
func (q *Queue) Write(data []uint8) (int, error) { func (q *Queue) Write(data []uint8) (int, error) {
more := uint32(len(data)) more := uint32(len(data))
// Nothing to copy from is an error regardless of mode.
if more == 0 { if more == 0 {
return 0, ErrWriteBuffer return 0, ErrWriteBuffer
} // nothing to copy from
tail := q.tail.Get()
used := tail - q.head.Get()
if used == QueueSize {
return 0, ErrQueueFull
} // full queue
if used+more > QueueSize {
more = QueueSize - used
} // only put to unused space
for i := uint32(0); i < more; i++ {
q.fifo[tail%QueueSize] = data[i]
tail++
} }
q.tail.Set(tail)
return int(more), nil switch q.mode {
} case QueueFullDiscardLast:
// drop incoming data
func (q *Queue) Deq() (uint8, bool) {
tail := q.tail.Get()
tail := q.head.Get() used := tail - q.head.Get()
if tail == q.tail.Get() {
return 0, false // Full queue, cannot add any data.
} // empty queue if used == q.size.Get() {
return 0, ErrQueueFull
data := q.fifo[tail%QueueSize] }
q.head.Set(tail + 1)
// xOnly put to unused space.
return data, true if used+more > q.size.Get() {
more = q.size.Get() - used
}
// Copy a potentially-limited number of elements from data, depending on the
// current length of FIFO.
for i := uint32(0); i < more; i++ {
(*q.fifo)[tail%q.size.Get()] = data[i]
tail++
}
q.tail.Set(tail)
return int(more), nil
case QueueFullDiscardFirst:
// drop outgoing data
// Trying to write more data than the FIFO will hold will simply overwrite
// some of the given data, so there is no point writing that data.
from := uint32(0)
if more >= q.size.Get() {
// Begin copying only the data that will be kept.
from = more - q.size.Get()
// We can fill the entire FIFO.
more = q.size.Get()
// Reset the indices
q.head.Set(0)
q.tail.Set(0)
}
tail := q.tail.Get()
used := tail - q.head.Get()
// Make space for incoming data by discarding only as many FIFO elements as
// is necessary to store incoming data.
if used+more > q.size.Get() {
q.head.Set(tail + more - q.size.Get())
}
// Copy a potentially-limited number of elements from data, depending on the
// current length of FIFO.
for i := uint32(0); i < more; i++ {
(*q.fifo)[tail%q.size.Get()] = data[i]
tail++
}
}
} }
// Front returns the next element that would be dequeued from the receiver FIFO
// and true.
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
func (q *Queue) Front() (uint8, bool) { func (q *Queue) Front() (uint8, bool) {
tail := q.head.Get() head := q.head.Get()
if tail == q.tail.Get() { if head == q.tail.Get() {
return 0, false return 0, false
} // empty queue } // empty queue
return q.fifo[tail%QueueSize], true return (*q.fifo)[head%q.size.Get()], true
} }
func (q *Queue) Enq(data uint8) bool { // Back returns the last element that would be dequeued from the receiver FIFO
// and true.
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
func (q *Queue) Back() (uint8, bool) {
head := q.tail.Get() tail := q.tail.Get()
if head-q.head.Get() == QueueSize { if tail == q.head.Get() {
return false return 0, false
} // full queue } // empty queue
q.fifo[head%QueueSize] = data return (*q.fifo)[(tail-1)%q.size.Get()], true
q.tail.Set(head + 1) }
return true // index returns an index into the receiver FIFO based on sign and magnitude of i:
// 1. If i is greater than or equal to zero and less then q.Len(), returns the
// (i+1)'th element that would be dequeued from the receiver FIFO and true.
// 2. Otherwise, if i is negative and -i is less than or equal to q.Len(), returns
// the -(i+1)'th from the last element that would be dequeued from the receiver
// FIFO and true.
// 3. Otherwise, returns 0 and false.
func (q *Queue) index(i int) (int, bool) {
if n := q.Len(); i < 0 {
if -i <= n {
return (int(q.tail.Get()) + i) % int(q.size.Get()), true
}
} else {
if i < n {
return (int(q.head.Get()) + i) % int(q.size.Get()), true
}
}
return 0, false
}
// Get returns the value of an element in the receiver FIFO, offset by i from the
// front of the queue if i is positive, or from the back of the queue if i is
// negative. For example:
// Get(0) == Get(-Len()) == Front(), and
// Get(-1) == Get(Len()-1) == Back().
// If the offset is beyond queue boundaries, returns 0 and false.
func (q *Queue) Get(i int) (uint8, bool) {
if n, ok := q.index(i); ok {
return (*q.fifo)[n], true
}
return 0, false
}
// Set modifies the value of an element in the receiver FIFO.
// Set uses the same logic as Get to select an element in the FIFO.
func (q *Queue) Set(i int, data uint8) bool {
if n, ok := q.index(i); ok {
(*q.fifo)[n] = data
return true
}
return false
} }