begin USB refactor with package machine/usb2

This commit is contained in:
ardnew
2021-03-28 15:46:03 -05:00
committed by sago35
parent 87a4676137
commit 6583ec1448
29 changed files with 5626 additions and 121 deletions
+9
View File
@@ -0,0 +1,9 @@
package usb2
type dci interface {
init() status
enable(enable bool) status
critical(enter bool) status
interrupt()
udelay(micros uint32)
}
+194
View File
@@ -0,0 +1,194 @@
// +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 {
dc.bus.BURSTSIZE.Set(0x0404)
// if dc.phy.PWD.HasBits((nxp.USBPHY_PWD_RXPWDRX | nxp.USBPHY_PWD_RXPWDDIFF |
// nxp.USBPHY_PWD_RXPWD1PT1 | nxp.USBPHY_PWD_RXPWDENV |
// nxp.USBPHY_PWD_TXPWDV2I | nxp.USBPHY_PWD_TXPWDIBIAS |
// nxp.USBPHY_PWD_TXPWDFS)) ||
// dc.bus.USBMODE.HasBits(nxp.USB_USBMODE_CM_Msk) {
// // reset controller if it was already enabled
// 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_SFTRST)
// }
// 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
// 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 {
dc.irq.SetPriority(dciInterruptPriority)
dc.irq.Enable()
dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_RS)
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`)
}
}
+334
View File
@@ -0,0 +1,334 @@
package usb2
const descUSBSpecVersion = 0x0200 // USB 2.0
// 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
// Descriptor type
descTypeDevice = 0x01
descTypeConfigure = 0x02
descTypeString = 0x03
descTypeInterface = 0x04
descTypeEndpoint = 0x05
descTypeDeviceQualitier = 0x06
descTypeOtherSpeedConfiguration = 0x07
descTypeInterfacePower = 0x08
descTypeOTG = 0x09
descTypeInterfaceAssociation = 0x0B
descTypeBOS = 0x0F
descTypeDeviceCapability = 0x10
descTypeHID = 0x21
descTypeHIDReport = 0x22
descTypeHIDPhysical = 0x23
descTypeCDCInterface = 0x24
descTypeCDCEndpoint = 0x25
descTypeEndpointCompanion = 0x30
// Configuration attributes
descConfigAttrD7Msk = 0x80
descConfigAttrD7Pos = 7
descConfigAttrSelfPoweredMsk = 0x40
descConfigAttrSelfPoweredPos = 6
descConfigAttrRemoteWakeupMsk = 0x20
descConfigAttrRemoteWakeupPos = 5
// Endpoint type
descEndptTypeControl = 0x00
descEndptTypeIsochronous = 0x01
descEndptTypeBulk = 0x02
descEndptTypeInterrupt = 0x03
// Endpoint address
descEndptAddrNumberMsk = 0x0F
descEndptAddrNumberPos = 0
descEndptAddrDirectionMsk = 0x80
descEndptAddrDirectionPos = 7
descEndptAddrDirectionOut = 0
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
// Endpoint max packet size
descEndptMaxPktSizeSizeMsk = 0x07FF
descEndptMaxPktSizeMultTransMsk = 0x1800
descEndptMaxPktSizeMultTransPos = 11
descEndptMaxPktSizeMaximum = 64
// OTG attributes
descOTGAttrSRPMsk = 0x01
descOTGAttrHNPMsk = 0x02
descOTGAttrADPMsk = 0x04
// Device capability type
descDevCapTypeWireless = 0x01
descDevCapTypeUSB20Extension = 0x02
descDevCapTypeSuperspeed = 0x03
// Device capability attributes (USB 2.0 extension)
descDevCapExtAttrLPMMsk = 0x02
descDevCapExtAttrLPMPos = 1
descDevCapExtAttrBESLMsk = 0x04
descDevCapExtAttrBESLPos = 2
)
// USB CDC constants defined per specification.
const (
// Device class
descCDCComm = 0x02 // communication/control
descCDCData = 0x0A // data
// Communication/control subclass
descCDCSubNone = 0x00
descCDCSubDirectLineControl = 0x01
descCDCSubAbstractControl = 0x02
descCDCSubTelephoneControl = 0x03
descCDCSubMultiChannelControl = 0x04
descCDCSubCAPIControl = 0x05
descCDCSubEthernetNetworkingControl = 0x06
descCDCSubATMNetworkingControl = 0x07
descCDCSubWirelessHandsetControl = 0x08
descCDCSubDeviceManagement = 0x09
descCDCSubMobileDirectLine = 0x0A
descCDCSubOBEX = 0x0B
descCDCSubEthernetEmulation = 0x0C
// Communication/control protocol
descCDCProtoNone = 0x00 // also for data class
descCDCProtoAT250 = 0x01
descCDCProtoATPCCA101 = 0x02
descCDCProtoATPCCA101AnnexO = 0x03
descCDCProtoATGSM707 = 0x04
descCDCProtoAT3GPP27007 = 0x05
descCDCProtoATTIACDMA = 0x06
descCDCProtoEthernetEmulation = 0x07
descCDCProtoExternal = 0xFE
descCDCProtoVendorSpecific = 0xFF // also for data class
// Data protocol
descCDCProtoPyhsicalInterface = 0x30
descCDCProtoHDLC = 0x31
descCDCProtoTransparent = 0x32
descCDCProtoManagement = 0x50
descCDCProtoDataLinkQ931 = 0x51
descCDCProtoDataLinkQ921 = 0x52
descCDCProtoDataCompressionV42BIS = 0x90
descCDCProtoEuroISDN = 0x91
descCDCProtoRateAdaptionISDNV24 = 0x92
descCDCProtoCAPICommands = 0x93
descCDCProtoHostBasedDriver = 0xFD
descCDCProtoUnitFunctional = 0xFE
// Functional descriptor length
descCDCLengthFuncHeader = 5
descCDCLengthFuncCallManagement = 5
descCDCLengthFuncAbstractControl = 4
descCDCLengthFuncUnion = 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
)
// 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
// 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
descLengthEndpoint + // communication/control input endpoint
descLengthInterface + // data interface
descLengthEndpoint + // data input endpoint
descLengthEndpoint) // data output endpoint
// Attributes of all CDC-ACM configuration descriptors.
descCDCACMConfigAttr = descConfigAttrD7Msk | // Bit 7: reserved (1)
(1 << descConfigAttrSelfPoweredPos) | // Bit 6: self-powered
(0 << descConfigAttrRemoteWakeupPos) | // Bit 5: remote wakeup
0 // Bits 0-4: reserved (0)
)
// 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
},
}
// 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
},
}
)
+32
View File
@@ -0,0 +1,32 @@
package usb2
// descCPUFrequencyHz defines the target CPU frequency (Hz).
const descCPUFrequencyHz = 600000000
// General USB device identification constants.
const (
descVendorID = 0xABCD
descProductID = 0x1234
descReleaseID = 0x0101
descVendor = "NXP Semiconductors"
descProduct = "TinyGo USB"
)
// 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
descCDCACMMaxPower = 50 // 100 mA
descCDCACMStatusPacketSize = 16
descCDCACMDataRxPacketSize = descCDCACMDataRxFSPacketSize // full-speed
descCDCACMDataTxPacketSize = descCDCACMDataTxFSPacketSize // full-speed
descCDCACMDataRxFSPacketSize = 64 // full-speed
descCDCACMDataTxFSPacketSize = 64 // full-speed
descCDCACMDataRxHSPacketSize = 512 // high-speed
descCDCACMDataTxHSPacketSize = 512 // high-speed
)
+9
View File
@@ -0,0 +1,9 @@
package usb2
type hci interface {
init() status
enable(enable bool) status
critical(enter bool) status
interrupt()
udelay(micros uint32)
}
+126
View File
@@ -0,0 +1,126 @@
// +build mimxrt1062
package usb2
// Implementation of USB host controller interface (hci) for NXP iMXRT1062.
import (
"device/arm"
"device/nxp"
"runtime/interrupt"
"runtime/volatile"
)
// hciCount 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
// hciInterruptPriority defines the priority for all USB host interrupts.
const hciInterruptPriority = 3
// hostController implements USB host controller interface (hci).
type hostController struct {
core *core // Parent USB core this instance is attached to
port int // USB port index
id int // hostControllerInstance 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
}
// hostControllerInstance provides statically-allocated instances of each USB
// host controller configured on this platform.
var hostControllerInstance [hciCount]hostController
// initHCI 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
}
// Return the first instance whose assigned core is currently nil.
for i := range hostControllerInstance {
if nil == hostControllerInstance[i].core {
// Initialize host controller.
hostControllerInstance[i].core = &coreInstance[port]
hostControllerInstance[i].port = port
hostControllerInstance[i].id = i
switch port {
case 0:
hostControllerInstance[i].bus = nxp.USB1
hostControllerInstance[i].phy = nxp.USBPHY1
hostControllerInstance[i].irq =
interrupt.New(nxp.IRQ_USB_OTG1,
func(interrupt.Interrupt) {
coreInstance[0].hc.interrupt()
})
case 1:
hostControllerInstance[i].bus = nxp.USB2
hostControllerInstance[i].phy = nxp.USBPHY2
hostControllerInstance[i].irq =
interrupt.New(nxp.IRQ_USB_OTG2,
func(interrupt.Interrupt) {
//coreInstance[1].hc.interrupt()
})
}
return &hostControllerInstance[i], statusOK
}
}
return nil, statusBusy // No free host controller instances available.
}
func (hc *hostController) init() status {
return statusOK
}
func (hc *hostController) enable(enable bool) status {
hc.irq.SetPriority(hciInterruptPriority)
hc.irq.Enable()
return statusOK
}
func (hc *hostController) critical(enter bool) status {
if enter {
// check if critical section already locked
if hc.cri.Get() != 0 {
return statusRetry
}
// lock critical section
hc.cri.Set(1)
// disable interrupts, storing state in receiver
hc.ivm = arm.DisableInterrupts()
} else {
// ensure critical section is locked
if hc.cri.Get() != 0 {
// re-enable interrupts, using state stored in receiver
arm.EnableInterrupts(hc.ivm)
// unlock critical section
hc.cri.Set(0)
}
}
return statusOK
}
func (hc *hostController) interrupt() {
}
// 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 (hc *hostController) udelay(microsec uint32) {
n := cycles(microsec, descCPUFrequencyHz)
for i := uint32(0); i < n; i++ {
arm.Asm(`nop`)
}
}
+53
View File
@@ -0,0 +1,53 @@
package usb2
import (
"errors"
)
var (
ErrInvalidPort = errors.New("invalid USB port")
)
type (
UARTConfig struct {
BaudRate uint32
}
// UART represents a virtual serial (UART) device emulation using the USB
// CDC-ACM device class driver.
UART struct {
port int // USB port (core index, e.g., 0-1)
core *core
}
)
func (uart *UART) Configure(config UARTConfig) error {
if uart.port >= CoreCount || uart.port >= dciCount ||
uart.port >= descCDCACMConfigCount {
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)
if !st.ok() {
return ErrInvalidPort
}
return nil
}
+99
View File
@@ -0,0 +1,99 @@
package usb2
// Hardware abstraction for USB ports configured as either host or device.
// 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
}
// Constant definitions for USB core operating modes.
const (
modeIdle = 0
modeDevice = 1
modeHost = 2
)
// CoreCount defines the total number of USB cores to configure in device or
// host mode.
const CoreCount = dciCount + hciCount
// coreInstance provides statically-allocated instances of each USB core
// configured on this platform.
var coreInstance [CoreCount]core
// status represents the return code of a subroutine.
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
)
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) {
if port < 0 || port >= CoreCount {
return nil, statusInvalidArgument
}
if modeIdle != coreInstance[port].mode {
return nil, statusBusy
}
switch mode {
case modeDevice:
// Allocate a free device controller and install interrupts
dc, st := initDCI(port)
if !st.ok() {
return nil, st
}
// Initialize buffers and device descriptors
if st = dc.init(); !st.ok() {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = mode
coreInstance[port].dc = dc
// Enable interrupts and enter runtime
if st = dc.enable(true); !st.ok() {
coreInstance[port].mode = modeIdle
coreInstance[port].dc = nil
return nil, st
}
case modeHost:
// Allocate a free host controller and install interrupts
hc, st := initHCI(port)
if !st.ok() {
return nil, st
}
// Initialize buffers and device descriptors
if st = hc.init(); !st.ok() {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = mode
coreInstance[port].hc = hc
// Enable interrupts and enter runtime
if st = hc.enable(true); !st.ok() {
coreInstance[port].mode = modeIdle
coreInstance[port].hc = nil
return nil, st
}
default:
return nil, statusInvalidArgument
}
return &coreInstance[port], statusOK
}
+194
View File
@@ -0,0 +1,194 @@
package usb2
// leU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 7 is the most-
// significant byte.
//go:inline
func leU64(u uint64) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0, 0, 0, 0, 0, 0, 0}
}
return []uint8{
uint8(u), uint8(u >> 8), uint8(u >> 16), uint8(u >> 24),
uint8(u >> 32), uint8(u >> 40), uint8(u >> 48), uint8(u >> 56),
}
}
// leU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 3 is the most-
// significant byte.
//go:inline
func leU32(u uint32) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0, 0, 0}
}
return []uint8{
uint8(u), uint8(u >> 8), uint8(u >> 16), uint8(u >> 24),
}
}
// leU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 1 is the most-
// significant byte.
//go:inline
func leU16(u uint16) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0}
}
return []uint8{
uint8(u), uint8(u >> 8),
}
}
// beU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 7 is the least-
// significant byte.
//go:inline
func beU64(u uint64) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0, 0, 0, 0, 0, 0, 0}
}
return []uint8{
uint8(u >> 56), uint8(u >> 48), uint8(u >> 40), uint8(u >> 32),
uint8(u >> 24), uint8(u >> 16), uint8(u >> 8), uint8(u),
}
}
// beU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 3 is the least-
// significant byte.
//go:inline
func beU32(u uint32) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0, 0, 0}
}
return []uint8{
uint8(u >> 24), uint8(u >> 16), uint8(u >> 8), uint8(u),
}
}
// beU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 1 is the least-
// significant byte.
//go:inline
func beU16(u uint16) []uint8 {
if u == 0 {
// skip all processing for the common case (u = 0)
return []uint8{0, 0}
}
return []uint8{
uint8(u >> 8), uint8(u),
}
}
// revU64 returns the given uint64 u with bytes in the reverse order.
//go:inline
func revU64(u uint64) uint64 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00000000000000FF) << 56) |
((u & 0x000000000000FF00) << 40) |
((u & 0x0000000000FF0000) << 24) |
((u & 0x00000000FF000000) << 8) |
((u & 0x000000FF00000000) >> 8) |
((u & 0x0000FF0000000000) >> 24) |
((u & 0x00FF000000000000) >> 40) |
((u & 0xFF00000000000000) >> 56)
}
// revU32 returns the given uint32 u with bytes in the reverse order.
//go:inline
func revU32(u uint32) uint32 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x000000FF) << 24) | ((u & 0x0000FF00) << 8) |
((u & 0x00FF0000) >> 8) | ((u & 0xFF000000) >> 24)
}
// revU16 returns the given uint16 u with bytes in the reverse order.
//go:inline
func revU16(u uint16) uint16 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00FF) << 8) | ((u & 0xFF00) >> 8)
}
// packU64 returns a uint64 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 7, if given. If fewer
// than 8 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU64(b []uint8) (u uint64) {
for i := 0; i < 8 && i < len(b); i++ {
u |= uint64(b[i]) << (i * 8)
}
return
}
// packU32 returns a uint32 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 3, if given. If fewer
// than 4 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU32(b []uint8) (u uint32) {
for i := 0; i < 4 && i < len(b); i++ {
u |= uint32(b[i]) << (i * 8)
}
return
}
// packU16 returns a uint16 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 1, if given. If fewer
// than 2 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU16(b []uint8) (u uint16) {
for i := 0; i < 2 && i < len(b); i++ {
u |= uint16(b[i]) << (i * 8)
}
return
}
// msU8 returns the most-significant byte of u.
//go:inline
func msU8(u uint16) uint8 { return uint8(u >> 8) }
// lsU8 returns the least-significant byte of u.
//go:inline
func lsU8(u uint16) uint8 { return uint8(u) }
// cycles converts the given number of microseconds to CPU cycles for a CPU with
// given frequency.
//go:inline
func cycles(microsec, cpuFreqHz uint32) uint32 {
return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000)
}