Files
tinygo/src/machine/usb/desc-cdc_atsamd51.go
T
sago35 4b81985d2b refactor USB package with device class build tags
added basic HID keyboard support for SAMx51 (not fully-functional)
2022-05-30 18:18:35 +09:00

242 lines
8.1 KiB
Go

//go:build baremetal && usb.cdc && (atsamd51 || atsame5x)
// +build baremetal
// +build usb.cdc
// +build atsamd51 atsame5x
package usb
import "runtime/volatile"
// Constants for USB CDC-ACM device classes.
const (
// USB Bus Configuration Attributes
descCDCMaxPowerMa = 100 // Maximum current (mA) requested from host
// CDC-ACM Endpoint Descriptor Buffers
descCDCEDCount = descMaxEndpoints
// Setup packet is only 8 bytes in length. However, under certain scenarios,
// USB DMA controller may decide to overwrite/overflow the buffer with 2 extra
// bytes of CRC. From datasheet's "Management of SETUP Transactions" section:
// | If the number of received data bytes is the maximum data payload
// | specified by PCKSIZE.SIZE minus one, only the first CRC data is written
// | to the data buffer. If the number of received data is equal or less
// | than the data payload specified by PCKSIZE.SIZE minus two, both CRC
// | data bytes are written to the data buffer.
// Thus, we need to allocate 2 extra bytes for control endpoint 0 Rx (OUT).
descCDCSxSize = 8 + 2
descCDCCxSize = descControlPacketSize
// CDC-ACM Data Buffers
descCDCRxSize = descCDCDataRxPacketSize
descCDCTxSize = descCDCDataTxPacketSize
descCDCTxTimeoutMs = 120 // millisec
descCDCTxSyncUs = 75 // microsec
// Default CDC-ACM Endpoint Configurations (Full-Speed)
descCDCStatusInterval = descCDCStatusFSInterval // Status
descCDCStatusPacketSize = descCDCStatusFSPacketSize //
descCDCDataRxPacketSize = descCDCDataRxFSPacketSize // Data Rx
descCDCDataTxPacketSize = descCDCDataTxFSPacketSize // Data Tx
// CDC-ACM Endpoint Configurations for Full-Speed Device
descCDCStatusFSInterval = 5 // Status
descCDCStatusFSPacketSize = 64 // (full-speed)
descCDCDataRxFSPacketSize = 64 // Data Rx (full-speed)
descCDCDataTxFSPacketSize = 64 // Data Tx (full-speed)
// CDC-ACM Endpoint Configurations for High-Speed Device
// - N/A, SAMx51 only has a full-speed PHY
)
// descCDC0ED is an array of endpoint descriptors, which describes to the USB
// DMA controller the buffer and transfer properties for each endpoint, for the
// default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0ED [descCDCEDCount]dhwEPAddrDesc
// descCDC0Sx is the receive (Rx) buffer for setup packets on control endpoint
// 0 of the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0Sx [descCDCSxSize]uint8
// descCDC0Cx is the transmit (Tx) buffer for control/status packets on control
// endpoint 0 of the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0Cx [descCDCCxSize]uint8
// descCDC0Dx is the transmit (Tx) buffer of descriptor data on endpoint 0
// for the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0Dx [descCDCConfigSize]uint8
// descCDC0Rx is the receive (Rx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Rx [descCDCRxSize]uint8
// descCDC0Tx is the transmit (Tx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Tx [descCDCTxSize]uint8
// descCDC0Rq is the receive (Rx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Rq [descCDCRxSize]uint8
// descCDC0Tq is the transmit (Tx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Tq [descCDCTxSize]uint8
// descCDC0LC is the emulated UART's line coding configuration for the
// default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0LC descCDCLineCoding
// descCDC0LS is the emulated UART's line state for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0LS descCDCLineState
// descCDCState defines the state of the CDC-ACM handshake initialization.
//
// Many USB hosts will send a default SET_LINE_CODING prior to SET_LINE_STATE,
// and then another SET_LINE_CODING containing the actual terminal settings.
//
// We do not want to start UART Rx/Tx transactions until after we have
// received the final SET_LINE_CODING with the intended terminal settings.
// Otherwise, the host may cancel any data transfers occurring during a change
// in line state or line coding.
//
// The "set" method on type descCDCState defines this incremental state
// machine, with the UART's current state stored in the volatile.Register8
// field "st" of descCDCClassData.
type descCDCState uint8
// set implements the state transition logic described in the godoc comment on
// type descCDCState. Returns the value of the resulting state.
//go:inline
func (s *descCDCState) set(state descCDCState) descCDCState {
if state > *s {
// state must be incremented in-order. Otherwise, reset to initial state.
if state == *s+1 {
*s = state
} else {
var init descCDCState // Reset to zero-value of type.
*s = init
}
}
// Return a value for safely chaining the result.
// (Not a pointer to the object we just modified.)
return *s
}
const (
descCDCStateConfigured descCDCState = iota // Received SET_CONFIGURATION class request
descCDCStateLineState // Received SET_LINE_STATE after Configured state
descCDCStateLineCoding // Received SET_LINE_CODING after LineState state
)
// descCDCClassData holds the buffers and control states for all CDC-ACM
// (single) device class configurations, ordered by index (offset by -1), for
// SAMx51 targets only.
//
// Instances of this type (elements of descCDCData) are embedded in elements
// of the common/target-agnostic CDC-ACM class configurations (descCDC).
// Methods defined on this type implement target-specific functionality, and
// some of these methods are required by the common device controller driver.
// Thus, this type functions as a hardware abstraction layer (HAL).
type descCDCClassData struct {
// CDC-ACM Control Buffers
ed *[descCDCEDCount]dhwEPAddrDesc // endpoint descriptors
sx *[descCDCSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
cx *[descCDCCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
dx *[descCDCConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
// CDC-ACM Data Buffers
rx *[descCDCRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
tx *[descCDCTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
rxq *[descCDCRxSize]uint8 // CDC-ACM UART Rx FIFO
txq *[descCDCTxSize]uint8 // CDC-ACM UART Tx FIFO
rq *Queue // CDC-ACM UART Rx Queue (backed by FIFO rxq)
tq *Queue // CDC-ACM UART Tx Queue (backed by FIFO txq)
lc *descCDCLineCoding // UART line coding
ls *descCDCLineState // UART line state
st volatile.Register8
sxSize uint32
rxSize uint32
txSize uint32
}
// setState is a wrapper for converting and storing the given descCDCState
// value as a uint8 in the receiver's volatile.Register8 field st.
//go:inline
func (c *descCDCClassData) setState(state descCDCState) {
s := descCDCState(c.st.Get())
c.st.Set(uint8(s.set(state)))
}
// state is a wrapper for retrieving and converting the receiver's
// volatile.Register8 field st from uint8 to descCDCState.
//go:inline
func (c *descCDCClassData) state() descCDCState {
return descCDCState(c.st.Get())
}
// descCDCData holds statically-allocated instances for each of the target-
// specific (SAMx51) CDC-ACM (single) device class configurations' control and
// data structures, ordered by configuration index (offset by -1). Each element
// is embedded in a corresponding element of descCDC.
var descCDCData = [dcdCount]descCDCClassData{
{ // -- CDC-ACM (single) Class Configuration Index 1 --
// CDC-ACM Control Buffers
ed: &descCDC0ED,
sx: &descCDC0Sx,
cx: &descCDC0Cx,
dx: &descCDC0Dx,
// CDC-ACM Data Buffers
rx: &descCDC0Rx,
tx: &descCDC0Tx,
rxq: &descCDC0Rq,
txq: &descCDC0Tq,
rq: &Queue{},
tq: &Queue{},
lc: &descCDC0LC,
ls: &descCDC0LS,
sxSize: descCDCStatusPacketSize,
rxSize: descCDCDataRxPacketSize,
txSize: descCDCDataTxPacketSize,
},
}