functioning ACM device registration with host

This commit is contained in:
ardnew
2021-04-19 03:10:42 -05:00
committed by sago35
parent a041a7866d
commit 8103b3c3c8
13 changed files with 2066 additions and 441 deletions
+81
View File
@@ -252,3 +252,84 @@ func enableDcache(enable bool) {
}
}
}
// FlushDcache flushes data from cache to memory
//
// Normally FlushDcache is used when metadata written to memory will be used by
// a DMA or a bus-controller peripheral. Any data in the cache is written to
// memory. A copy remains in the cache, so this is typically used with special
// fields you will want to quickly access in the future. For data transmission,
// use FlushDeleteDcache.
//go:inline
func FlushDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCCMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
// DeleteDcache deletes data from the cache, without touching memory.
//
// Normally DeleteDcache is used before receiving data via DMA or from
// bus-controller peripherals which write to memory. You want to delete anything
// the cache may have stored, so your next read is certain to access the
// physical memory.
//go:inline
func DeleteDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCIMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
// FlushDeleteDcache flushes data from cache to memory, and delete it from the
// cache
//
// Normally FlushDeleteDcache is used when transmitting data via DMA or
// bus-controller peripherals which read from memory. You want any cached data
// written to memory, and then removed from the cache, because you no longer
// need to access the data after transmission.
//go:inline
func FlushDeleteDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCCIMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
+81
View File
@@ -0,0 +1,81 @@
package usb2
import "unsafe"
type dcd interface {
init() status
enable(enable bool) status
critical(enter bool) status
interrupt()
receive(endpoint uint8, transfer *dcdTransfer)
transmit(endpoint uint8, transfer *dcdTransfer)
control(setup dcdSetup)
}
const (
dcdEndpointSize = 64 // bytes
dcdTransferSize = 32 //
dcdSetupSize = 8 //
)
type dcdEndpoint struct {
config uint32 // 4
current *dcdTransfer // 4 *dcdTransfer
transfer dcdTransfer // 32
setup dcdSetup // 8
// Endpoints are 48-byte data structures. The remaining data extends this to
// 64-byte, and also makes it simpler for implementations to align endpoints
// allocated contiguously on 64-byte boundaries.
first *dcdTransfer // 4 *dcdTransfer
last *dcdTransfer // 4 *dcdTransfer
// After some discussion, perhaps the simplest change to support 64-bit (or
// future TinyGo versions that don't use 8 bytes to refer to a function) is to
// allocate a separate buffer of callbacks. The device controller would assign
// callbacks to unused elements in that buffer, and only the index of that
// callback would be stored here in the descriptor.
callback dcdTransferCallback // 8
}
type dcdTransferCallback func(transfer *dcdTransfer)
type dcdTransfer struct {
next *dcdTransfer // 4 *dcdTransfer
token uint32 // 4
pointer [5]uintptr // 20
param uint32 // 4
}
type dcdSetup struct {
bmRequestType uint8
bRequest uint8
wValue uint16
wIndex uint16
wLength uint16
}
func (s dcdSetup) pack() uint64 {
return ((uint64(s.bmRequestType) & 0xFF) << 0) | // uint8
((uint64(s.bRequest) & 0xFF) << 8) | // uint8
((uint64(s.wValue) & 0xFFFF) << 16) | // uint16
((uint64(s.wIndex) & 0xFFFF) << 32) | // uint16
((uint64(s.wLength) & 0xFFFF) << 48) // uint16
}
var (
// dcdPointerNil is a sentinel value used to indicate a pointer to an invalid
// value. Do not attempt to dereference!
dcdPointerNil = uintptr(0)
// dcdTransferEOL is a sentinel value used to indicate the final node in a
// linked list of transfer descriptors.
dcdTransferEOL = (*dcdTransfer)(unsafe.Pointer(dcdTransferPointerEOL))
// dcdTransferPointerEOL is the notional memory address of dcdTransferEOL.
// The address does not refer to an actual dcdTransfer, so no attempt should
// be made to dereference it.
dcdTransferPointerEOL = uintptr(1)
)
// nextTransfer returns the next transfer descriptor pointed to by the receiver
// transfer descriptor, and whether or not that next descriptor is the final
// descriptor in the list.
func (t *dcdTransfer) nextTransfer() (*dcdTransfer, bool) {
return t.next, uintptr(unsafe.Pointer(t.next)) == dcdTransferPointerEOL
}
File diff suppressed because it is too large Load Diff
-174
View File
@@ -1,174 +0,0 @@
// +build mimxrt1062
package usb2
// Implementation of USB device controller interface (dci) for NXP iMXRT1062.
import (
"device/arm"
"device/nxp"
"runtime/interrupt"
"runtime/volatile"
"strconv"
)
// dciCount defines the number of USB cores to configure for device mode. It is
// computed as the sum of all declared device configuration descriptors.
const dciCount = descCDCACMConfigCount
// dciInterruptPriority defines the priority for all USB device interrupts.
const dciInterruptPriority = 3
// deviceController implements USB device controller interface (dci).
type deviceController struct {
core *core // Parent USB core this instance is attached to
port int // USB port index
id int // deviceControllerInstance index
bus *nxp.USB_Type
phy *nxp.USBPHY_Type
irq interrupt.Interrupt
cri volatile.Register8 // set to 1 if in critical section, else 0
ivm uintptr // interrupt state when entering critical section
}
// deviceControllerInstance provides statically-allocated instances of each USB
// device controller configured on this platform.
var deviceControllerInstance [dciCount]deviceController
// initDCI initializes and assigns a free device controller instance to the
// given USB port. Returns the initialized device controller or nil if no free
// device controller instances remain.
func initDCI(port int) (dci, status) {
if 0 == dciCount {
return nil, statusInvalidArgument // must have defined device descriptors
}
// Return the first instance whose assigned core is currently nil.
for i := range deviceControllerInstance {
if nil == deviceControllerInstance[i].core {
// Initialize device controller.
deviceControllerInstance[i].core = &coreInstance[port]
deviceControllerInstance[i].port = port
deviceControllerInstance[i].id = i
switch port {
case 0:
deviceControllerInstance[i].bus = nxp.USB1
deviceControllerInstance[i].phy = nxp.USBPHY1
deviceControllerInstance[i].irq =
interrupt.New(nxp.IRQ_USB_OTG1,
func(interrupt.Interrupt) {
coreInstance[0].dc.interrupt()
})
case 1:
deviceControllerInstance[i].bus = nxp.USB2
deviceControllerInstance[i].phy = nxp.USBPHY2
deviceControllerInstance[i].irq =
interrupt.New(nxp.IRQ_USB_OTG2,
func(interrupt.Interrupt) {
//coreInstance[1].dc.interrupt()
})
}
return &deviceControllerInstance[i], statusOK
}
}
return nil, statusBusy // No free device controller instances available.
}
func (dc *deviceController) init() status {
// reset the controller
dc.phy.CTRL_SET.Set(nxp.USBPHY_CTRL_SFTRST)
dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_RST)
for dc.bus.USBCMD.HasBits(nxp.USB_USBCMD_RST) {
}
// clear interrupts
m := arm.DisableInterrupts()
switch dc.port {
case 0:
arm.EnableInterrupts(m & ^uintptr(nxp.IRQ_USB_OTG1))
case 1:
arm.EnableInterrupts(m & ^uintptr(nxp.IRQ_USB_OTG2))
}
dc.phy.CTRL_CLR.Set(nxp.USBPHY_CTRL_CLKGATE | nxp.USBPHY_CTRL_SFTRST)
dc.phy.PWD.Set(0)
// clear the controller mode field and set to device mode:
// controller mode (CM) 0x0=idle, 0x2=device-only, 0x3=host-only
dc.bus.USBMODE.ReplaceBits(nxp.USB_USBMODE_CM_CM_2,
nxp.USB_USBMODE_CM_Msk>>nxp.USB_USBMODE_CM_Pos, nxp.USB_USBMODE_CM_Pos)
dc.bus.USBCMD.ClearBits(nxp.USB_USBCMD_ITC_Msk) // no interrupt threshold
dc.bus.USBMODE.SetBits(nxp.USB_USBMODE_SLOM_Msk) // disable setup lockout
dc.bus.USBMODE.ClearBits(nxp.USB_USBMODE_ES_Msk) // use little-endianness
// TODO: configure ENDPOINTLISTADDR
// enable interrupts
dc.bus.USBINTR.Set(
nxp.USB_USBINTR_UE_Msk | // bus enable
nxp.USB_USBINTR_UEE_Msk | // bus error
nxp.USB_USBINTR_PCE_Msk | // port change detect
nxp.USB_USBINTR_URE_Msk | // bus reset
nxp.USB_USBINTR_SLE) // sleep enable
// ensure D+ pulled down long enough for host to detect previous disconnect
dc.udelay(5000)
return statusOK
}
func (dc *deviceController) enable(enable bool) status {
if enable {
dc.irq.SetPriority(dciInterruptPriority)
dc.irq.Enable()
dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_RS)
} else {
dc.bus.USBCMD.ClearBits(nxp.USB_USBCMD_RS)
dc.irq.Disable()
}
return statusOK
}
func (dc *deviceController) critical(enter bool) status {
if enter {
// check if critical section already locked
if dc.cri.Get() != 0 {
return statusRetry
}
// lock critical section
dc.cri.Set(1)
// disable interrupts, storing state in receiver
dc.ivm = arm.DisableInterrupts()
} else {
// ensure critical section is locked
if dc.cri.Get() != 0 {
// re-enable interrupts, using state stored in receiver
arm.EnableInterrupts(dc.ivm)
// unlock critical section
dc.cri.Set(0)
}
}
return statusOK
}
func (dc *deviceController) interrupt() {
// read and clear the interrupts that fired
status := dc.bus.USBSTS.Get() & dc.bus.USBINTR.Get()
dc.bus.USBSTS.Set(status)
println(strconv.FormatUint(uint64(status), 16))
}
// udelay waits for the given number of microseconds before returning.
// We cannot use the sleep timer from this context (import cycle), but we need
// an approximate method to spin CPU cycles for short periods of time.
//go:inline
func (dc *deviceController) udelay(microsec uint32) {
n := cycles(microsec, descCPUFrequencyHz)
for i := uint32(0); i < n; i++ {
arm.Asm(`nop`)
}
}
+390 -199
View File
@@ -1,21 +1,29 @@
package usb2
const descUSBSpecVersion = 0x0200 // USB 2.0
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
const descLanguageEnglish = uint16(0x0409)
type descIndexStrings [4][64]uint8
type descLocalStrings struct {
language uint16
index descIndexStrings // UTF-16, 32-character maximum length
}
// USB constants defined per specification.
const (
// Descriptor length
descLengthDevice = 18
descLengthConfigure = 9
descLengthInterface = 9
descLengthEndpoint = 7
descLengthDeviceQualitier = 10
descLengthOTG = 5
descLengthBOS = 5
descLengthEndpointCompanion = 6
descLengthDevCapTypeUSB20Extension = 7
descLengthDevCapTypeSuperspeed = 10
descLengthDevice = 18
descLengthConfigure = 9
descLengthInterface = 9
descLengthEndpoint = 7
descLengthQualification = 10
descLengthOTG = 5
descLengthBOS = 5
descLengthEndpointCompanion = 6
descLengthUSB20Extension = 7
descLengthSuperspeed = 10
// Descriptor type
descTypeDevice = 0x01
@@ -23,7 +31,7 @@ const (
descTypeString = 0x03
descTypeInterface = 0x04
descTypeEndpoint = 0x05
descTypeDeviceQualitier = 0x06
descTypeQualification = 0x06
descTypeOtherSpeedConfiguration = 0x07
descTypeInterfacePower = 0x08
descTypeOTG = 0x09
@@ -37,6 +45,36 @@ const (
descTypeCDCEndpoint = 0x25
descTypeEndpointCompanion = 0x30
// Standard request type
descRequestTypeDirMsk = 0x80
descRequestTypeDirPos = 7
descRequestTypeDirOut = 0x00
descRequestTypeDirIn = 0x80
descRequestTypeTypeMsk = 0x60
descRequestTypeTypePos = 5
descRequestTypeTypeStandard = 0
descRequestTypeTypeClass = 0x20
descRequestTypeTypeVendor = 0x40
descRequestTypeRecipientMsk = 0x1F
descRequestTypeRecipientPos = 0
descRequestTypeRecipientDevice = 0x00
descRequestTypeRecipientInterface = 0x01
descRequestTypeRecipientEndpoint = 0x02
descRequestTypeRecipientOther = 0x03
// Standard request
descRequestStandardGetStatus = 0x00
descRequestStandardClearFeature = 0x01
descRequestStandardSetFeature = 0x03
descRequestStandardSetAddress = 0x05
descRequestStandardGetDescriptor = 0x06
descRequestStandardSetDescriptor = 0x07
descRequestStandardGetConfiguration = 0x08
descRequestStandardSetConfiguration = 0x09
descRequestStandardGetInterface = 0x0A
descRequestStandardSetInterface = 0x0B
descRequestStandardSynchFrame = 0x0C
// Configuration attributes
descConfigAttrD7Msk = 0x80
descConfigAttrD7Pos = 7
@@ -60,49 +98,55 @@ const (
descEndptAddrDirectionIn = 0x80
// Endpoint attributes
descEndptAttrTypeMsk = 0x03
descEndptAttrNumberPos = 0
descEndptAttrSyncTypeMsk = 0x0C
descEndptAttrSyncTypePos = 2
descEndptAttrSyncTypeNoSync = 0x00
descEndptAttrSyncTypeAsync = 0x04
descEndptAttrSyncTypeAdaptive = 0x08
descEndptAttrSyncTypeSync = 0x0C
descEndptAttrUsageTypeMsk = 0x30
descEndptAttrUsageTypePos = 4
descEndptAttrUsageTypeDataEndpoint = 0x00
descEndptAttrUsageTypeFeedEndpoint = 0x10
descEndptAttrUsageTypeFeedDataEndpoint = 0x20
descEndptAttrTypeMsk = 0x03
descEndptAttrNumberPos = 0
descEndptAttrSyncTypeMsk = 0x0C
descEndptAttrSyncTypePos = 2
descEndptAttrSyncTypeNoSync = 0x00
descEndptAttrSyncTypeAsync = 0x04
descEndptAttrSyncTypeAdaptive = 0x08
descEndptAttrSyncTypeSync = 0x0C
descEndptAttrUsageTypeMsk = 0x30
descEndptAttrUsageTypePos = 4
descEndptAttrUsageTypeData = 0x00
descEndptAttrUsageTypeFeed = 0x10
descEndptAttrUsageTypeFeedData = 0x20
// Endpoint max packet size
descEndptMaxPktSizeSizeMsk = 0x07FF
descEndptMaxPktSizeMultTransMsk = 0x1800
descEndptMaxPktSizeMultTransPos = 11
descEndptMaxPktSizeMaximum = 64
descEndptMaxPktSizeMsk = 0x07FF
descEndptMaxPktSize = 64
descEndptMaxPktSizeMultMsk = 0x1800
descEndptMaxPktSizeMultPos = 11
// OTG attributes
descOTGAttrSRPMsk = 0x01
descOTGAttrHNPMsk = 0x02
descOTGAttrADPMsk = 0x04
// Device bus speed
descDeviceSpeedFull = 0x00
descDeviceSpeedLow = 0x01
descDeviceSpeedHigh = 0x02
descDeviceSpeedSuper = 0x04
// Device capability type
descDevCapTypeWireless = 0x01
descDevCapTypeUSB20Extension = 0x02
descDevCapTypeSuperspeed = 0x03
descDeviceCapTypeWireless = 0x01
descDeviceCapTypeUSB20Extension = 0x02
descDeviceCapTypeSuperspeed = 0x03
// Device capability attributes (USB 2.0 extension)
descDevCapExtAttrLPMMsk = 0x02
descDevCapExtAttrLPMPos = 1
descDevCapExtAttrBESLMsk = 0x04
descDevCapExtAttrBESLPos = 2
descDeviceCapExtAttrLPMMsk = 0x02
descDeviceCapExtAttrLPMPos = 1
descDeviceCapExtAttrBESLMsk = 0x04
descDeviceCapExtAttrBESLPos = 2
)
// USB CDC constants defined per specification.
const (
// Device class
descCDCComm = 0x02 // communication/control
descCDCData = 0x0A // data
descCDCTypeComm = 0x02 // communication/control
descCDCTypeData = 0x0A // data
// Communication/control subclass
descCDCSubNone = 0x00
@@ -146,60 +190,133 @@ const (
descCDCProtoUnitFunctional = 0xFE
// Functional descriptor length
descCDCLengthFuncHeader = 5
descCDCLengthFuncCallManagement = 5
descCDCLengthFuncAbstractControl = 4
descCDCLengthFuncUnion = 5
descCDCFuncLengthHeader = 5
descCDCFuncLengthCallManagement = 5
descCDCFuncLengthAbstractControl = 4
descCDCFuncLengthUnion = 5
// Functional descriptor type
descCDCTypeFuncHeader = 0x00
descCDCTypeFuncCallManagement = 0x01
descCDCTypeFuncAbstractControl = 0x02
descCDCTypeFuncDirectLine = 0x03
descCDCTypeFuncTelephoneRinger = 0x04
descCDCTypeFuncTelephoneReport = 0x05
descCDCTypeFuncUnion = 0x06
descCDCTypeFuncCountrySelect = 0x07
descCDCTypeFuncTelephoneModes = 0x08
descCDCTypeFuncTerminal = 0x09
descCDCTypeFuncNetworkChannel = 0x0A
descCDCTypeFuncProtocolUnit = 0x0B
descCDCTypeFuncExtensionUnit = 0x0C
descCDCTypeFuncMultiChannel = 0x0D
descCDCTypeFuncCAPIControl = 0x0E
descCDCTypeFuncEthernetNetworking = 0x0F
descCDCTypeFuncATMNetworking = 0x10
descCDCTypeFuncWirelessControl = 0x11
descCDCTypeFuncMobileDirectLine = 0x12
descCDCTypeFuncMDLMDetail = 0x13
descCDCTypeFuncDeviceManagement = 0x14
descCDCTypeFuncOBEX = 0x15
descCDCTypeFuncCommandSet = 0x16
descCDCTypeFuncCommandSetDetail = 0x17
descCDCTypeFuncTelephoneControl = 0x18
descCDCTypeFuncOBEXServiceID = 0x19
descCDCFuncTypeHeader = 0x00
descCDCFuncTypeCallManagement = 0x01
descCDCFuncTypeAbstractControl = 0x02
descCDCFuncTypeDirectLine = 0x03
descCDCFuncTypeTelephoneRinger = 0x04
descCDCFuncTypeTelephoneReport = 0x05
descCDCFuncTypeUnion = 0x06
descCDCFuncTypeCountrySelect = 0x07
descCDCFuncTypeTelephoneModes = 0x08
descCDCFuncTypeTerminal = 0x09
descCDCFuncTypeNetworkChannel = 0x0A
descCDCFuncTypeProtocolUnit = 0x0B
descCDCFuncTypeExtensionUnit = 0x0C
descCDCFuncTypeMultiChannel = 0x0D
descCDCFuncTypeCAPIControl = 0x0E
descCDCFuncTypeEthernetNetworking = 0x0F
descCDCFuncTypeATMNetworking = 0x10
descCDCFuncTypeWirelessControl = 0x11
descCDCFuncTypeMobileDirectLine = 0x12
descCDCFuncTypeMDLMDetail = 0x13
descCDCFuncTypeDeviceManagement = 0x14
descCDCFuncTypeOBEX = 0x15
descCDCFuncTypeCommandSet = 0x16
descCDCFuncTypeCommandSetDetail = 0x17
descCDCFuncTypeTelephoneControl = 0x18
descCDCFuncTypeOBEXServiceID = 0x19
// Standard request
descCDCRequestSendEncapsulatedCommand = 0x00 // CDC request SEND_ENCAPSULATED_COMMAND
descCDCRequestGetEncapsulatedResponse = 0x01 // CDC request GET_ENCAPSULATED_RESPONSE
descCDCRequestSetCommFeature = 0x02 // CDC request SET_COMM_FEATURE
descCDCRequestGetCommFeature = 0x03 // CDC request GET_COMM_FEATURE
descCDCRequestClearCommFeature = 0x04 // CDC request CLEAR_COMM_FEATURE
descCDCRequestSetAuxLineState = 0x10 // CDC request SET_AUX_LINE_STATE
descCDCRequestSetHookState = 0x11 // CDC request SET_HOOK_STATE
descCDCRequestPulseSetup = 0x12 // CDC request PULSE_SETUP
descCDCRequestSendPulse = 0x13 // CDC request SEND_PULSE
descCDCRequestSetPulseTime = 0x14 // CDC request SET_PULSE_TIME
descCDCRequestRingAuxJack = 0x15 // CDC request RING_AUX_JACK
descCDCRequestSetLineCoding = 0x20 // CDC request SET_LINE_CODING
descCDCRequestGetLineCoding = 0x21 // CDC request GET_LINE_CODING
descCDCRequestSetControlLineState = 0x22 // CDC request SET_CONTROL_LINE_STATE
descCDCRequestSendBreak = 0x23 // CDC request SEND_BREAK
descCDCRequestSetRingerParams = 0x30 // CDC request SET_RINGER_PARAMS
descCDCRequestGetRingerParams = 0x31 // CDC request GET_RINGER_PARAMS
descCDCRequestSetOperationParam = 0x32 // CDC request SET_OPERATION_PARAM
descCDCRequestGetOperationParam = 0x33 // CDC request GET_OPERATION_PARAM
descCDCRequestSetLineParams = 0x34 // CDC request SET_LINE_PARAMS
descCDCRequestGetLineParams = 0x35 // CDC request GET_LINE_PARAMS
descCDCRequestDialDigits = 0x36 // CDC request DIAL_DIGITS
descCDCRequestSetUnitParameter = 0x37 // CDC request SET_UNIT_PARAMETER
descCDCRequestGetUnitParameter = 0x38 // CDC request GET_UNIT_PARAMETER
descCDCRequestClearUnitParameter = 0x39 // CDC request CLEAR_UNIT_PARAMETER
descCDCRequestSetEthernetMulticastFilters = 0x40 // CDC request SET_ETHERNET_MULTICAST_FILTERS
descCDCRequestSetEthernetPowPatternFilter = 0x41 // CDC request SET_ETHERNET_POW_PATTER_FILTER
descCDCRequestGetEthernetPowPatternFilter = 0x42 // CDC request GET_ETHERNET_POW_PATTER_FILTER
descCDCRequestSetEthernetPacketFilter = 0x43 // CDC request SET_ETHERNET_PACKET_FILTER
descCDCRequestGetEthernetStatistic = 0x44 // CDC request GET_ETHERNET_STATISTIC
descCDCRequestSetATMDataFormat = 0x50 // CDC request SET_ATM_DATA_FORMAT
descCDCRequestGetATMDeviceStatistics = 0x51 // CDC request GET_ATM_DEVICE_STATISTICS
descCDCRequestSetATMDefaultVC = 0x52 // CDC request SET_ATM_DEFAULT_VC
descCDCRequestGetATMVCStatistics = 0x53 // CDC request GET_ATM_VC_STATISTICS
descCDCRequestMDLMSpecificRequestsMask = 0x7F // CDC request MDLM_SPECIFIC_REQUESTS_MASK
// Notification type
descCDCNotifyNetworkConnection = 0x00 // CDC notify NETWORK_CONNECTION
descCDCNotifyResponseAvail = 0x01 // CDC notify RESPONSE_AVAIL
descCDCNotifyAuxJackHookState = 0x08 // CDC notify AUX_JACK_HOOK_STATE
descCDCNotifyRingDetect = 0x09 // CDC notify RING_DETECT
descCDCNotifySerialState = 0x20 // CDC notify SERIAL_STATE
descCDCNotifyCallStateChange = 0x28 // CDC notify CALL_STATE_CHANGE
descCDCNotifyLineStateChange = 0x29 // CDC notify LINE_STATE_CHANGE
descCDCNotifyConnectionSpeedChange = 0x2A // CDC notify CONNECTION_SPEED_CHANGE
// Feature select
descCDCFeatureAbstractState = 0x01 // CDC feature select ABSTRACT_STATE
descCDCFeatureCountrySetting = 0x02 // CDC feature select COUNTRY_SETTING
// Control signal
descCDCControlSigBitmapCarrierActivation = 0x02 // CDC control signal CARRIER_ACTIVATION
descCDCControlSigBitmapDTEPresence = 0x01 // CDC control signal DTE_PRESENCE
// UART emulated state
descCDCUARTStateRxCarrier = 0x01 // UART state RX_CARRIER
descCDCUARTStateTxCarrier = 0x02 // UART state TX_CARRIER
descCDCUARTStateBreak = 0x04 // UART state BREAK
descCDCUARTStateRingSignal = 0x08 // UART state RING_SIGNAL
descCDCUARTStateFraming = 0x10 // UART state FRAMING
descCDCUARTStateParity = 0x20 // UART state PARITY
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
)
// Common configuration constants for the USB CDC-ACM (single) device class.
const (
// Interfaces for the first CDC-ACM device (index 1).
descCDCACM0InterfaceCount = 2
descCDCACM0InterfaceCtrl = 0
descCDCACM0InterfaceData = 1
// Endpoints for the first CDC-ACM device (index 1).
descCDCACM0EndpointCount = 4
descCDCACM0EndpointStatus = 2 // Communication/control interrupt input
descCDCACM0EndpointDataRx = 3 // Bulk data output
descCDCACM0EndpointDataTx = 4 // Bulk data input
// String descriptor languages
descCDCACMLanguageCount = 1
// Interfaces for all CDC-ACM configurations.
descCDCACMInterfaceCount = 2
descCDCACMInterfaceCtrl = 0
descCDCACMInterfaceData = 1
// Endpoints for all CDC-ACM configurations.
descCDCACMEndpointCount = 4
descCDCACMEndpointStatus = 2 // Communication/control interrupt input
descCDCACMEndpointDataRx = 3 // Bulk data output
descCDCACMEndpointDataTx = 4 // Bulk data input
// Endpoint configuration attributes for all CDC-ACM configurations.
descCDCACMConfigAttrStatus = (descCDCACMConfigAttrUnused << descCDCACMConfigAttrRxPos) |
(descCDCACMConfigAttrInterrupt << descCDCACMConfigAttrTxPos)
descCDCACMConfigAttrDataRx = (descCDCACMConfigAttrBulk << descCDCACMConfigAttrRxPos) |
(descCDCACMConfigAttrUnused << descCDCACMConfigAttrTxPos)
descCDCACMConfigAttrDataTx = (descCDCACMConfigAttrUnused << descCDCACMConfigAttrRxPos) |
(descCDCACMConfigAttrBulk << descCDCACMConfigAttrTxPos)
// Size of all CDC-ACM configuration descriptors.
descCDCACMConfigSize = uint16(
descLengthConfigure + // configuration
descLengthInterface + // communication/control interface
descCDCLengthFuncHeader + // CDC header
descCDCLengthFuncCallManagement + // CDC call management
descCDCLengthFuncAbstractControl + // CDC abstract control
descCDCLengthFuncUnion + // CDC union
descCDCFuncLengthHeader + // CDC header
descCDCFuncLengthCallManagement + // CDC call management
descCDCFuncLengthAbstractControl + // CDC abstract control
descCDCFuncLengthUnion + // CDC union
descLengthEndpoint + // communication/control input endpoint
descLengthInterface + // data interface
descLengthEndpoint + // data input endpoint
@@ -209,126 +326,200 @@ const (
(1 << descConfigAttrSelfPoweredPos) | // Bit 6: self-powered
(0 << descConfigAttrRemoteWakeupPos) | // Bit 5: remote wakeup
0 // Bits 0-4: reserved (0)
descCDCACMConfigAttrRxPos = 0
descCDCACMConfigAttrTxPos = 16
descCDCACMConfigAttrUnused = 0x02 // TBD: what is this?
descCDCACMConfigAttrIsochronous = descCDCACMConfigAttr | descEndptAttrSyncTypeAsync
descCDCACMConfigAttrBulk = descCDCACMConfigAttr | descEndptAttrSyncTypeAdaptive
descCDCACMConfigAttrInterrupt = descCDCACMConfigAttr | descEndptAttrSyncTypeSync
)
// Common descriptors for the USB CDC-ACM (single) device class.
var (
// descDeviceCDCACM holds the default device descriptors for CDC-ACM devices.
descDeviceCDCACM = [descCDCACMConfigCount][descLengthDevice]uint8{
{
descLengthDevice, // Size of this descriptor in bytes
descTypeDevice, // DEVICE Descriptor Type
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
descCDCComm, // Class code (assigned by the USB-IF).
descCDCSubNone, // Subclass code (assigned by the USB-IF).
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSizeMaximum, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
lsU8(descVendorID), // Vendor ID (low) (assigned by the USB-IF)
msU8(descVendorID), // Vendor ID (high) (assigned by the USB-IF)
lsU8(descProductID), // Product ID (low) (assigned by the manufacturer)
msU8(descProductID), // Product ID (high) (assigned by the manufacturer)
lsU8(descReleaseID), // Device release number in BCD (low)
msU8(descReleaseID), // Device release number in BCD (high)
1, // Index of string descriptor describing manufacturer
2, // Index of string descriptor describing product
0, // Index of string descriptor describing the device's serial number
descCDCACMConfigCount, // Number of possible configurations
// descCDCACM0String holds the default string descriptors for CDC-ACM[0], i.e.,
// configuration index 1.
var descCDCACM0String = [descCDCACMLanguageCount]descLocalStrings{
{
language: descLanguageEnglish,
index: descIndexStrings{
{ // 0: language string
4,
descTypeString,
lsU8(descLanguageEnglish),
msU8(descLanguageEnglish),
},
{ // 1: manufacturer
uint8(2 + 2*len(descManufacturer)),
descTypeString,
},
{ // 2: product
uint8(2 + 2*len(descProduct)),
descTypeString,
},
{ // 3: serial number
uint8(2 + 2*len(descSerialNumber)),
descTypeString,
},
},
},
}
// descCDCACM0Device holds the default device descriptor for CDC-ACM[0], i.e.,
// configuration index 1.
var descCDCACM0Device = [descLengthDevice]uint8{
descLengthDevice, // Size of this descriptor in bytes
descTypeDevice, // Descriptor Type
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
descCDCTypeComm, // Class code (assigned by the USB-IF).
descCDCSubNone, // Subclass code (assigned by the USB-IF).
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
lsU8(descVendorID), // Vendor ID (low) (assigned by the USB-IF)
msU8(descVendorID), // Vendor ID (high) (assigned by the USB-IF)
lsU8(descProductID), // Product ID (low) (assigned by the manufacturer)
msU8(descProductID), // Product ID (high) (assigned by the manufacturer)
lsU8(descReleaseID), // Device release number in BCD (low)
msU8(descReleaseID), // Device release number in BCD (high)
1, // Index of string descriptor describing manufacturer
2, // Index of string descriptor describing product
3, // Index of string descriptor describing the device's serial number
descCDCACMCount, // Number of possible configurations
}
// descCDCACM0Qualif holds the default device qualification descriptor for
// CDC-ACM[0], i.e., configuration index 1.
var descCDCACM0Qualif = [descLengthQualification]uint8{
descLengthQualification, // Size of this descriptor in bytes
descTypeQualification, // Descriptor Type
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
descCDCTypeComm, // Class code (assigned by the USB-IF).
descCDCSubNone, // Subclass code (assigned by the USB-IF).
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
descCDCACMCount, // Number of possible configurations
0, // Reserved
}
// descCDCACM0Config holds the default configuration descriptors for CDC-ACM[0],
// i.e., configuration index 1.
var descCDCACM0Config = [descCDCACMConfigSize]uint8{
descLengthConfigure, // Size of this descriptor in bytes
descTypeConfigure, // Descriptor Type
lsU8(descCDCACMConfigSize), // Total length of data returned for this configuration (low)
msU8(descCDCACMConfigSize), // Total length of data returned for this configuration (high)
descCDCACMInterfaceCount, // Number of interfaces supported by this configuration
1, // Value to use to select this configuration (1 = CDC-ACM[0])
0, // Index of string descriptor describing this configuration
descCDCACMConfigAttr, // Configuration attributes
descCDCACMMaxPower, // Max power consumption when fully-operational (2 mA units)
// Communication/Control Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descCDCACMInterfaceCtrl, // Interface index
0, // Alternate setting
1, // Number of endpoints
descCDCTypeComm, // Class code
descCDCSubAbstractControl, // Subclass code
descCDCProtoNone, // Protocol code (NOTE: Teensyduino defines this as 1 [AT V.250])
0, // Interface Description String Index
// CDC Header Functional Descriptor
descCDCFuncLengthHeader, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCFuncTypeHeader, // Descriptor Subtype
0x10, // USB CDC specification version 1.10 (low)
0x01, // USB CDC specification version 1.10 (high)
// CDC Call Management Functional Descriptor
descCDCFuncLengthCallManagement, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCFuncTypeCallManagement, // Descriptor Subtype
0x01, // Capabilities
descCDCACMInterfaceData, // Data Interface
// CDC Abstract Control Management Functional Descriptor
descCDCFuncLengthAbstractControl, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCFuncTypeAbstractControl, // Descriptor Subtype
0x06, // Capabilities
// CDC Union Functional Descriptor
descCDCFuncLengthUnion, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCFuncTypeUnion, // Descriptor Subtype
descCDCACMInterfaceCtrl, // Controlling interface index
descCDCACMInterfaceData, // Controlled interface index
// Communication/Control Notification Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACMEndpointStatus | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descCDCACMStatusPacketSize), // Max packet size (low)
msU8(descCDCACMStatusPacketSize), // Max packet size (high)
16, // Polling Interval
// Data Interface Descriptor
descLengthInterface, // Interface length
descTypeInterface, // Interface type
descCDCACMInterfaceData, // Interface index
0, // Alternate setting
2, // Number of endpoints
descCDCTypeData, // Class code
descCDCSubNone, // Subclass code
descCDCProtoNone, // Protocol code
0, // Interface Description String Index
// Data Bulk Rx Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACMEndpointDataRx | // Endpoint address
descEndptAddrDirectionOut,
descEndptTypeBulk, // Attributes
lsU8(descCDCACMDataRxPacketSize), // Max packet size (low)
msU8(descCDCACMDataRxPacketSize), // Max packet size (high)
0, // Polling Interval
// Data Bulk Tx Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACMEndpointDataTx | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeBulk, // Attributes
lsU8(descCDCACMDataTxPacketSize), // Max packet size (low)
msU8(descCDCACMDataTxPacketSize), // Max packet size (high)
0, // Polling Interval
}
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
const descCDCACMCodingSize = 7
// descCDCACM0Coding holds the default UART line coding for CDC-ACM[0], i.e.,
// configuration index 1.
var descCDCACM0Coding [descCDCACMCodingSize]uint8
type descCDCACMLineCoding struct {
baud uint32
stopBits uint8
parity uint8
numBits uint8
dtr bool
rts bool
}
func (lc *descCDCACMLineCoding) parse(buffer []uint8) bool {
if len(buffer) < descCDCACMCodingSize {
return false
}
// descConfigCDCACM holds the default configuration descriptors for CDC-ACM
// devices.
descConfigCDCACM = [descCDCACMConfigCount][descCDCACMConfigSize]uint8{
{
descLengthConfigure, // Size of this descriptor in bytes
descTypeConfigure, // Descriptor Type
lsU8(descCDCACMConfigSize), // Total length of data returned for this configuration (low)
msU8(descCDCACMConfigSize), // Total length of data returned for this configuration (high)
descCDCACM0InterfaceCount, // Number of interfaces supported by this configuration
1, // Value to use to select this configuration (1 = CDC-ACM[0])
0, // Index of string descriptor describing this configuration
descCDCACMConfigAttr, // Configuration attributes
descCDCACMMaxPower, // Max power consumption when fully-operational (2 mA units)
// Communication/Control Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descCDCACM0InterfaceCtrl, // Interface index
0, // Alternate setting
1, // Number of endpoints
descCDCComm, // Class code
descCDCSubAbstractControl, // Subclass code
descCDCProtoNone, // Protocol code (NOTE: Teensyduino defines this as 1 [AT V.250])
0, // Interface Description String Index
// CDC Header Functional Descriptor
descCDCLengthFuncHeader, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCTypeFuncHeader, // Descriptor Subtype
0x10, // USB CDC specification version 1.10 (low)
0x01, // USB CDC specification version 1.10 (high)
// CDC Call Management Functional Descriptor
descCDCLengthFuncCallManagement, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCTypeFuncCallManagement, // Descriptor Subtype
0x01, // Capabilities
descCDCACM0InterfaceData, // Data Interface
// CDC Abstract Control Management Functional Descriptor
descCDCLengthFuncAbstractControl, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCTypeFuncAbstractControl, // Descriptor Subtype
0x06, // Capabilities
// CDC Union Functional Descriptor
descCDCLengthFuncUnion, // Size of this descriptor in bytes
descTypeCDCInterface, // Descriptor Type
descCDCTypeFuncUnion, // Descriptor Subtype
descCDCACM0InterfaceCtrl, // Controlling interface index
descCDCACM0InterfaceData, // Controlled interface index
// Communication/Control Notification Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACM0EndpointStatus | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descCDCACMStatusPacketSize), // Max packet size (low)
msU8(descCDCACMStatusPacketSize), // Max packet size (high)
8, // Polling Interval
// Data Interface Descriptor
descLengthInterface, // Interface length
descTypeInterface, // Interface type
descCDCACM0InterfaceData, // Interface index
0, // Alternate setting
2, // Number of endpoints
descCDCData, // Class code
descCDCSubNone, // Subclass code
descCDCProtoNone, // Protocol code
0, // Interface Description String Index
// Data Bulk Rx Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACM0EndpointDataRx | // Endpoint address
descEndptAddrDirectionOut,
descEndptTypeBulk, // Attributes
lsU8(descCDCACMDataRxPacketSize), // Max packet size (low)
msU8(descCDCACMDataRxPacketSize), // Max packet size (high)
0, // Polling Interval
// Data Bulk Tx Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCACM0EndpointDataTx | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeBulk, // Attributes
lsU8(descCDCACMDataTxPacketSize), // Max packet size (low)
msU8(descCDCACMDataTxPacketSize), // Max packet size (high)
0, // Polling Interval
},
lc.baud = packU32(buffer)
lc.stopBits = buffer[4]
if 0 == lc.stopBits {
lc.stopBits = 1
}
)
lc.parity = buffer[5]
lc.numBits = buffer[6]
return true
}
+166 -9
View File
@@ -1,3 +1,5 @@
// +build mimxrt1062
package usb2
// descCPUFrequencyHz defines the target CPU frequency (Hz).
@@ -5,28 +7,183 @@ const descCPUFrequencyHz = 600000000
// General USB device identification constants.
const (
descVendorID = 0xABCD
descProductID = 0x1234
descVendorID = 0x16C0
descProductID = 0x0483
descReleaseID = 0x0101
descVendor = "NXP Semiconductors"
descProduct = "TinyGo USB"
descManufacturer = "NXP Semiconductors"
descProduct = "TinyGo USB"
descSerialNumber = "0000000000"
)
// Constants for USB CDC-ACM device classes.
const (
// descCDCACMConfigCount defines the number of USB cores that will be
// configured as CDC-ACM (single) devices.
descCDCACMConfigCount = 1
// descCDCACMCount defines the number of USB cores that will be configured as
// CDC-ACM (single) devices.
descCDCACMCount = 1
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
descCDCACMRDCount = 2 * descCDCACMEndpointCount
descCDCACMTDCount = descCDCACMEndpointCount
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
descCDCACMCxCount = 8
descCDCACMMaxPower = 50 // 100 mA
descCDCACMStatusPacketSize = 16
descCDCACMDataRxPacketSize = descCDCACMDataRxFSPacketSize // full-speed
descCDCACMDataTxPacketSize = descCDCACMDataTxFSPacketSize // full-speed
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // high-speed
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // high-speed
descCDCACMRxSize = descCDCACMDataRxPacketSize
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
descCDCACMDataRxFSPacketSize = 64 // full-speed
descCDCACMDataTxFSPacketSize = 64 // full-speed
descCDCACMDataRxHSPacketSize = 512 // high-speed
descCDCACMDataTxHSPacketSize = 512 // high-speed
)
// descCDCACM0QH is an array of endpoint queue heads, which is where all
// transfers for a given endpoint are managed, for the default CDC-ACM (single)
// device class configuration (index 1).
//
// From the iMXRT1062 Reference Manual:
//
// Software must ensure that no interface data structure reachable
// by the Device Controller spans a 4K-page boundary.
//
// The [queue head] is a 48-byte data structure, but must be aligned on
// 64-byte boundaries.
//
// Endpoint queue heads are arranged in an array in a continuous area of
// memory pointed to by the USB.ENDPOINTLISTADDR pointer. The even-numbered
// device queue heads in the list support receive endpoints (OUT/SETUP) and
// the odd-numbered queue heads in the list are used for transmit endpoints
// (IN/INTERRUPT). The device controller will index into this array based upon
// the endpoint number received from the USB bus. All information necessary to
// respond to transactions for all primed transfers is contained in this list
// so the Device Controller can readily respond to incoming requests without
// having to traverse a linked list.
//go:align 4096
var descCDCACM0QH [descCDCACMQHCount]dcdEndpoint
// descCDCACM0CD is the transfer descriptor for data messages transmitted or
// received on the status/control endpoint 0 for the default CDC-ACM (single)
// device class configuration (index 1).
//go:align 32
var descCDCACM0CD dcdTransfer
// descCDCACM0AD is the transfer descriptor for ackowledgement (ACK) messages
// transmitted or received on the status/control endpoint 0 for the default
// CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDCACM0AD dcdTransfer
// descCDCACM0RD is an array of transfer descriptors for Rx (OUT) transfers,
// which describe to the device controller the location and quantity of data
// being received for a given transfer, for the default CDC-ACM (single) device
// class configuration (index 1).
//go:align 32
var descCDCACM0RD [descCDCACMRDCount]dcdTransfer
// descCDCACM0TD is an array of transfer descriptors for Tx (IN) transfers,
// which describe to the device controller the location and quantity of data
// being transmitted for a given transfer, for the default CDC-ACM (single)
// device class configuration (index 1).
//go:align 32
var descCDCACM0TD [descCDCACMTDCount]dcdTransfer
// descCDCACM0Cx is the buffer for control/status data received on endpoint 0 of
// the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDCACM0Cx [descCDCACMCxCount]uint8
// descCDCACM0Rx is the receive (Rx) buffer of data endpoints for the default
// CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDCACM0Rx [descCDCACMRxCount]uint8
// descCDCACM0Tx is the transmit (Tx) buffer of data endpoints for the default
// CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDCACM0Tx [descCDCACMTxCount]uint8
// descCDCACM0Dx is the transmit (Tx) buffer of descriptor data for the default
// CDC-ACM (single) device class configuration (index 1).
var descCDCACM0Dx [descCDCACMConfigSize]uint8
var descCDCACM0RDNum [descCDCACMRDCount]uint16
var descCDCACM0RDIdx [descCDCACMRDCount]uint16
var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
type descCDCACMClass struct {
locstr *[descCDCACMLanguageCount]descLocalStrings // string descriptors
device *[descLengthDevice]uint8 // device descriptor
qualif *[descLengthQualification]uint8 // device qualification descriptor
config *[descCDCACMConfigSize]uint8 // configuration descriptor
coding *[descCDCACMCodingSize]uint8 // UART line coding
cticks int64
rtsdtr uint8
qh *[descCDCACMQHCount]dcdEndpoint // endpoint queue heads
cd *dcdTransfer // control endpoint 0 Rx/Tx data transfer descriptor
ad *dcdTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
rd *[descCDCACMRDCount]dcdTransfer // bulk data endpoint Rx (OUT) transfer descriptors
td *[descCDCACMTDCount]dcdTransfer // bulk data endpoint Tx (IN) transfer descriptors
cx *[descCDCACMCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
rx *[descCDCACMRxCount]uint8 // bulk data endpoint Rx (OUT) transfer buffer
tx *[descCDCACMTxCount]uint8 // bulk data endpoint Tx (IN) transfer buffer
dx *[descCDCACMConfigSize]uint8 // descriptor data Tx (IN) transfer buffer
cxSize uint16
rxSize uint16
txSize uint16
txHead uint8
txFree uint16
rxHead uint8
rxTail uint8
rxFree uint16
rxCount *[descCDCACMRDCount]uint16
rxIndex *[descCDCACMRDCount]uint16
rxQueue *[descCDCACMRDCount + 1]uint16
}
// descCDCACM holds the configuration, endpoint, and transfer descriptors, along
// with the buffers and control states, for all of the CDC-ACM (single) device
// class configurations, ordered by configuration index (offset by -1).
var descCDCACM = [descCDCACMCount]descCDCACMClass{
{
locstr: &descCDCACM0String,
device: &descCDCACM0Device,
qualif: &descCDCACM0Qualif,
config: &descCDCACM0Config,
coding: &descCDCACM0Coding,
qh: &descCDCACM0QH,
cd: &descCDCACM0CD,
ad: &descCDCACM0AD,
rd: &descCDCACM0RD,
td: &descCDCACM0TD,
cx: &descCDCACM0Cx,
rx: &descCDCACM0Rx,
tx: &descCDCACM0Tx,
dx: &descCDCACM0Dx,
cxSize: descCDCACMStatusPacketSize,
rxSize: descCDCACMDataRxPacketSize,
txSize: descCDCACMDataTxPacketSize,
rxCount: &descCDCACM0RDNum,
rxIndex: &descCDCACM0RDIdx,
rxQueue: &descCDCACM0RDQue,
},
}
@@ -1,6 +1,6 @@
package usb2
type dci interface {
type hcd interface {
init() status
enable(enable bool) status
critical(enter bool) status
@@ -2,7 +2,7 @@
package usb2
// Implementation of USB host controller interface (hci) for NXP iMXRT1062.
// Implementation of USB host controller driver (hcd) for NXP iMXRT1062.
import (
"device/arm"
@@ -11,18 +11,19 @@ import (
"runtime/volatile"
)
// hciCount defines the number of USB cores to configure for host mode. It is
// hcdCount defines the number of USB cores to configure for host mode. It is
// computed as the sum of all declared host configuration descriptors.
const hciCount = 0
const hcdCount = 0
// hciInterruptPriority defines the priority for all USB host interrupts.
const hciInterruptPriority = 3
// hcdInterruptPriority defines the priority for all USB host interrupts.
const hcdInterruptPriority = 3
// hostController implements USB host controller interface (hci).
// hostController implements USB host controller driver (hcd) interface.
type hostController struct {
core *core // Parent USB core this instance is attached to
port int // USB port index
id int // hostControllerInstance index
core *core // Parent USB core this instance is attached to
port int // USB port index
class class // USB host class
id int // hostControllerInstance index
bus *nxp.USB_Type
phy *nxp.USBPHY_Type
@@ -34,14 +35,14 @@ type hostController struct {
// hostControllerInstance provides statically-allocated instances of each USB
// host controller configured on this platform.
var hostControllerInstance [hciCount]hostController
var hostControllerInstance [hcdCount]hostController
// initHCI initializes and assigns a free host controller instance to the given
// initHCD initializes and assigns a free host controller instance to the given
// USB port. Returns the initialized host controller or nil if no free host
// controller instances remain.
func initHCI(port int) (hci, status) {
if 0 == hciCount {
return nil, statusInvalidArgument // must have defined host descriptors
func initHCD(port int, class class) (hcd, status) {
if 0 == hcdCount {
return nil, statusInvalid // must have defined host controllers
}
// Return the first instance whose assigned core is currently nil.
for i := range hostControllerInstance {
@@ -82,7 +83,7 @@ func (hc *hostController) init() status {
func (hc *hostController) enable(enable bool) status {
hc.irq.SetPriority(hciInterruptPriority)
hc.irq.SetPriority(hcdInterruptPriority)
hc.irq.Enable()
return statusOK
-9
View File
@@ -1,9 +0,0 @@
package usb2
type hci interface {
init() status
enable(enable bool) status
critical(enter bool) status
interrupt()
udelay(micros uint32)
}
+2 -18
View File
@@ -23,29 +23,13 @@ type (
func (uart *UART) Configure(config UARTConfig) error {
if uart.port >= CoreCount || uart.port >= dciCount ||
uart.port >= descCDCACMConfigCount {
if uart.port >= CoreCount || uart.port >= dcdCount {
return ErrInvalidPort
}
// use default configuration index (1-based index; 0=invalid)
// uart.config = configDeviceCDCACMConfigurationIndex
// modify the global basic configuration struct configDeviceCDCACM for our USB
// port and configuration index.
//
// these settings are copied into the real CDC-ACM object, using interface
// deviceClassDriver, via initialization method (*deviceCDCACM).init().
// change baud rate from default, if provided
//if config.BaudRate != 0 {
// configDeviceCDCACM[uart.port][uart.config-1].lineCodingBaudRate =
// config.BaudRate
//}
// verify we have a free USB port and take ownership of it
var st status
uart.core, st = initCore(uart.port, modeDevice)
uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1})
if !st.ok() {
return ErrInvalidPort
}
+49 -16
View File
@@ -2,12 +2,20 @@ package usb2
// Hardware abstraction for USB ports configured as either host or device.
import "unsafe"
func init() {
if unsafe.Sizeof(uintptr(0)) > 4 {
panic("USB is only supported on 32-bit systems")
}
}
// core represents the core of a USB port configured as either host or device.
type core struct {
port int
mode int
dc dci
hc hci
dc dcd
hc hcd
}
// Constant definitions for USB core operating modes.
@@ -17,9 +25,32 @@ const (
modeHost = 2
)
// class represents the type of a host/device and its class configuration index.
// The first valid configuration index is 1. Index 0 is reserved and invalid.
type class struct {
id int
config int
}
// Constant definitions for all host/device classes.
const (
classDeviceCDCACM = 0 // The only currently-supported class (CDC-ACM)
)
// mode returns the USB core operating mode of the receiver class cl.
//go:inline
func (cl class) mode() int {
switch cl.id {
case classDeviceCDCACM:
return modeDevice
default:
return modeIdle
}
}
// CoreCount defines the total number of USB cores to configure in device or
// host mode.
const CoreCount = dciCount + hciCount
const CoreCount = dcdCount + hcdCount
// coreInstance provides statically-allocated instances of each USB core
// configured on this platform.
@@ -30,30 +61,32 @@ type status uint8
// Constant definitions for all status codes used within the package.
const (
statusOK status = iota // Success
statusBusy // Busy
statusRetry // Retry
statusInvalidArgument // Invalid argument
statusOK status = iota // Success
statusBusy // Busy
statusRetry // Retry
statusInvalid // Invalid argument
)
// ok returns true if and only if the receiver st equals statusOK.
//go:inline
func (st status) ok() bool { return statusOK == st }
// initCore initializes a free USB core with given operating mode on the USB
// port at given index, if available. Returns a reference to the initialized
// core or nil if the core is unavailable.
func initCore(port, mode int) (*core, status) {
func initCore(port int, class class) (*core, status) {
if port < 0 || port >= CoreCount {
return nil, statusInvalidArgument
if port < 0 || port >= CoreCount || 0 == class.config {
return nil, statusInvalid
}
if modeIdle != coreInstance[port].mode {
return nil, statusBusy
}
switch mode {
switch class.mode() {
case modeDevice:
// Allocate a free device controller and install interrupts
dc, st := initDCI(port)
dc, st := initDCD(port, class)
if !st.ok() {
return nil, st
}
@@ -62,7 +95,7 @@ func initCore(port, mode int) (*core, status) {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = mode
coreInstance[port].mode = modeDevice
coreInstance[port].dc = dc
// Enable interrupts and enter runtime
if st = dc.enable(true); !st.ok() {
@@ -73,7 +106,7 @@ func initCore(port, mode int) (*core, status) {
case modeHost:
// Allocate a free host controller and install interrupts
hc, st := initHCI(port)
hc, st := initHCD(port, class)
if !st.ok() {
return nil, st
}
@@ -82,7 +115,7 @@ func initCore(port, mode int) (*core, status) {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = mode
coreInstance[port].mode = modeHost
coreInstance[port].hc = hc
// Enable interrupts and enter runtime
if st = hc.enable(true); !st.ok() {
@@ -92,7 +125,7 @@ func initCore(port, mode int) (*core, status) {
}
default:
return nil, statusInvalidArgument
return nil, statusInvalid
}
return &coreInstance[port], statusOK
+22
View File
@@ -192,3 +192,25 @@ func lsU8(u uint16) uint8 { return uint8(u) }
func cycles(microsec, cpuFreqHz uint32) uint32 {
return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000)
}
//go:inline
func unpackEndpoint(address uint8) (number, direction uint8) {
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos,
(address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
}
//go:inline
func rxEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionOut
}
//go:inline
func txEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionIn
}
//go:inline
func endpointIndex(address uint8) uint8 {
return ((address & descEndptAddrNumberMsk) << 1) |
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
}
+16
View File
@@ -0,0 +1,16 @@
// +build arm
package usb2
import "device/arm"
// udelay waits for the given number of microseconds before returning.
// We cannot use the sleep timer from this context (import cycle), but we need
// an approximate method to spin CPU cycles for short periods of time.
//go:inline
func udelay(microsec uint32) {
n := cycles(microsec, descCPUFrequencyHz)
for i := uint32(0); i < n; i++ {
arm.Asm(`nop`)
}
}