mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-12 23:13:40 +00:00
4b81985d2b
added basic HID keyboard support for SAMx51 (not fully-functional)
242 lines
8.1 KiB
Go
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,
|
|
},
|
|
}
|