implemented USB HID composite keyboard support

This commit is contained in:
ardnew
2021-05-02 18:05:36 -05:00
committed by sago35
parent 34b931b6f3
commit d2a1835ffc
16 changed files with 3459 additions and 496 deletions
View File
+251
View File
@@ -0,0 +1,251 @@
package main
import (
"machine"
"machine/usb"
"time"
)
var keyboard = machine.HID0.Keyboard()
func main() {
println("USB HID keyboard demo")
for {
time.Sleep(5 * time.Second)
// Open a new text editor
keyboard.Down(usb.KeyModifierAlt)
keyboard.Press(usb.KeySpace)
keyboard.Up(usb.KeyModifierAlt)
time.Sleep(2 * time.Second)
keyboard.Write([]byte("kate"))
time.Sleep(time.Second)
keyboard.Press(usb.KeyEnter)
time.Sleep(5 * time.Second)
// Use the io.Writer interface
keyboard.Write([]byte("TinyGo USB Keyboard Control Test\n"))
time.Sleep(2 * time.Second)
// Or manually specify keycodes and Unicode codepoints
testKeys([]Key{
// Print alphabet out-of-order
{Press: usb.KeyX},
{Press: usb.KeyY},
{Press: usb.KeyZ},
{Press: usb.KeyG},
{Press: usb.KeyH},
{Press: usb.KeyI},
{Press: usb.KeyJ},
{Press: usb.KeyK},
{Press: usb.KeyL},
{Press: usb.KeyM},
{Press: usb.KeyN},
{Press: usb.KeyO},
{Press: usb.KeyP},
{Press: usb.KeyQ},
{Press: usb.KeyR},
{Press: usb.KeyS},
{Press: usb.KeyT},
{Press: usb.KeyA},
{Press: usb.KeyB},
{Press: usb.KeyC},
{Press: usb.KeyD},
{Press: usb.KeyE},
{Press: usb.KeyF},
{Press: usb.KeyU},
{Press: usb.KeyV},
{Press: usb.KeyW},
// Pause 1 second
{Time: time.Second},
// Move cursor left x3
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
// Pause 1 second
{Time: time.Second},
// Highlight 6 symbols to the left
{Down: usb.KeyModifierShift},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Press: usb.KeyLeft},
{Up: usb.KeyModifierShift},
// Pause 1 second
{Time: time.Second},
// Use Ctrl-X to cut
{Down: usb.KeyModifierCtrl, Press: usb.KeyX, Up: usb.KeyModifierCtrl},
// Pause 1 second
{Time: time.Second},
// Move to beginning of line
{Press: usb.KeyHome},
// Pause 1 second
{Time: time.Second},
// Use Ctrl-V to paste
{Down: usb.KeyModifierCtrl, Press: usb.KeyV, Up: usb.KeyModifierCtrl},
// Pause 1 second
{Time: time.Second},
// Highlight 3 symbols to the right
{Down: usb.KeyModifierShift},
{Press: usb.KeyRight},
{Press: usb.KeyRight},
{Press: usb.KeyRight},
{Up: usb.KeyModifierShift},
// Use Ctrl-X to cut
{Down: usb.KeyModifierCtrl, Press: usb.KeyX, Up: usb.KeyModifierCtrl},
// Pause 1 second
{Time: time.Second},
// Move to end of line
{Press: usb.KeyEnd},
// Pause 1 second
{Time: time.Second},
// Use Ctrl-V to paste
{Down: usb.KeyModifierCtrl, Press: usb.KeyV, Up: usb.KeyModifierCtrl},
// Pause 1 second
{Time: time.Second},
// Newline
{Press: usb.KeyEnter},
{Press: usb.KeyEnter},
}, 150*time.Millisecond)
// Highlight all text and delete
keyboard.Down(usb.KeyModifierCtrl)
keyboard.Press(usb.KeyA)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(time.Second)
keyboard.Press(usb.KeyDelete)
time.Sleep(time.Second)
// Close window
keyboard.Down(usb.KeyModifierCtrl)
keyboard.Press(usb.KeyQ)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(2 * time.Second)
// Confirm discard file
keyboard.Down(usb.KeyModifierAlt)
keyboard.Press(usb.KeyD)
keyboard.Up(usb.KeyModifierAlt)
time.Sleep(5 * time.Second)
// Open a new terminal
keyboard.Down(usb.KeyModifierAlt)
keyboard.Press(usb.KeySpace)
keyboard.Up(usb.KeyModifierAlt)
time.Sleep(2 * time.Second)
keyboard.Write([]byte("konsole"))
keyboard.Press(usb.KeyEnter)
time.Sleep(5 * time.Second)
// Open serial connection
keyboard.Write([]byte("screen /dev/ttyACM0 115200"))
time.Sleep(2 * time.Second)
keyboard.Press(usb.KeyEnter)
time.Sleep(4 * time.Second)
// Write to UART
keyboard.Write([]byte("hello!"))
time.Sleep(time.Second)
keyboard.Press(usb.KeyEnter)
time.Sleep(2 * time.Second)
keyboard.Write([]byte("NO U"))
time.Sleep(time.Second)
keyboard.Press(usb.KeyEnter)
time.Sleep(2 * time.Second)
// Close serial connection
keyboard.Down(usb.KeyModifierCtrl)
keyboard.Press(usb.KeyX)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(time.Second)
keyboard.Press(usb.KeyBackslash)
time.Sleep(time.Second)
keyboard.Press(usb.KeyY)
keyboard.Press(usb.KeyEnter)
time.Sleep(2 * time.Second)
// Close terminal
keyboard.Down(usb.KeyModifierCtrl)
keyboard.Press(usb.KeyD)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(25 * time.Second)
}
}
type Key struct {
Press usb.Keycode
Down usb.Keycode
Up usb.Keycode
Time time.Duration
}
func testKeys(key []Key, delay time.Duration) {
for _, k := range key {
if 0 != k.Down {
keyboard.Down(k.Down)
}
if 0 != k.Press {
keyboard.Press(k.Press)
}
if 0 != k.Up {
keyboard.Up(k.Up)
}
if 0 != k.Time {
time.Sleep(k.Time)
} else {
time.Sleep(delay)
}
}
}
func testInternationalLayout() {
// International keyboard layouts also supported
keyboard.Write([]byte("TinyGo USB Keyboard Layout Test\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Lowercase: abcdefghijklmnopqrstuvwxyz\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Numbers: 0123456789\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols1: !\"#$%&'()*+,-./\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols2: :;<=>?[\\]^_`{|}~\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols3: ¡¢£¤¥¦§¨©ª«¬­®¯°±\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols4: ²³´µ¶·¸¹º»¼½¾¿×÷\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Grave: ÀÈÌÒÙàèìòù\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Acute: ÁÉÍÓÚÝáéíóúý\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Circumflex: ÂÊÎÔÛâêîôû\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Tilde: ÃÑÕãñõ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Diaeresis: ÄËÏÖÜäëïöüÿ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Cedilla: Çç\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Ring Above: Åå\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("AE: Ææ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Thorn: Þþ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Sharp S: ß\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("O-Stroke: Øø\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Eth: Ðð\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Euro: €\n"))
}
+37
View File
@@ -0,0 +1,37 @@
// This is a echo console running on the device UART.
// Connect using default baudrate for this hardware, 8-N-1 with your terminal program.
package main
import (
"machine"
"time"
)
func main() {
uart := machine.UART0
uart.Write([]byte("Echo console enabled. Type something then press enter:\r\n"))
input := make([]byte, 4096)
i := 0
for {
if uart.Buffered() > 0 {
data, _ := uart.ReadByte()
switch data {
case 13:
// return key
uart.Write([]byte("\r\n"))
uart.Write([]byte("You typed: "))
uart.Write(input[:i])
uart.Write([]byte("\r\n"))
i = 0
default:
// just echo the character
uart.WriteByte(data)
input[i] = data
i++
}
}
time.Sleep(10 * time.Millisecond)
}
}
+4 -5
View File
@@ -5,6 +5,7 @@ package machine
import (
"device/nxp"
"machine/usb"
"runtime/interrupt"
)
@@ -109,11 +110,9 @@ func init() {
// | USB |
// #=====================================================#
var (
// USBCDC is a legacy class being retained here as temporary wrapper.
// See godoc comments on type USBCDC struct definition for details.
UART0 = USBCDC{
port: 0, // USB_OTG1 (Micro-B port on Teensy 4.0/4.1)
}
// UART0 = usb.UART{Port: 0}
HID0 = usb.HID{Port: 0}
UART0 = &UART1
)
// #=====================================================#
-49
View File
@@ -1,49 +0,0 @@
// +build mimxrt1062
package machine
import (
"machine/usb"
)
// USBCDC is the legacy TinyGo type used to implement USB CDC-ACM device class
// emulation for serial UART communication. It is retained here as a temporary
// wrapper for type usb.UART from new package "machine/usb", which is still in
// active development. Once that package has stabilized a bit, this type should
// be removed and usb.UART should be used directly instead.
type USBCDC struct {
port uint8
uart usb.UART
}
// Configure the embedded usb.UART with our receiver's settings and the given
// UART configuration. This provides compatibility with machine.UART.
func (cdc *USBCDC) Configure(config UARTConfig) {
cdc.uart.Configure(usb.UARTConfig{BaudRate: config.BaudRate})
}
// Buffered returns the number of bytes currently stored in the RX buffer.
func (cdc USBCDC) Buffered() int {
return cdc.uart.Buffered()
}
// ReadByte reads a single byte from the RX buffer.
// If there is no data in the buffer, returns an error.
func (cdc USBCDC) ReadByte() (byte, error) {
return cdc.uart.ReadByte()
}
// Read from the RX buffer.
func (cdc USBCDC) Read(data []byte) (n int, err error) {
return cdc.uart.Read(data)
}
// WriteByte writes a single byte of data to the UART interface.
func (cdc USBCDC) WriteByte(c byte) error {
return cdc.uart.WriteByte(c)
}
// Write data to the UART.
func (cdc USBCDC) Write(data []byte) (n int, err error) {
return cdc.uart.Write(data)
}
+469 -117
View File
@@ -12,7 +12,7 @@ func init() {
// dcdCount defines the number of USB cores to configure for device mode. It is
// computed as the sum of all declared device configuration descriptors.
const dcdCount = descCDCACMCount // + ...
const dcdCount = descCDCACMCount + descHIDCount
// dcdInstance provides statically-allocated instances of each USB device
// controller configured on this platform.
@@ -134,7 +134,6 @@ func (d *dcd) event(ev dcdEvent) {
case dcdStageSetup:
case dcdStageData:
case dcdStageStatus:
d.controlStatus()
case dcdStageStall:
d.controlStall()
}
@@ -180,7 +179,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// SET ADDRESS (0x05):
case descRequestStandardSetAddress:
d.controlDeviceAddress(sup.wValue)
d.setDeviceAddress(sup.wValue)
d.controlReceive(uintptr(0), 0, false)
return dcdStageSetup
@@ -200,6 +199,14 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
d.uartConfigure()
d.controlReceive(uintptr(0), 0, false)
// HID
case classDeviceHID:
d.serialConfigure()
d.keyboardConfigure()
d.mouseConfigure()
d.joystickConfigure()
d.controlReceive(uintptr(0), 0, false)
default:
// Unhandled device class
}
@@ -225,8 +232,23 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// GET DESCRIPTOR (0x06):
case descRequestStandardGetDescriptor:
d.controlDescriptor(sup)
return dcdStageSetup
// Respond based on our device class configuration
switch d.cc.id {
// CDC-ACM (single)
case classDeviceCDCACM:
d.controlDescriptorCDCACM(sup)
return dcdStageSetup
// HID
case classDeviceHID:
d.controlDescriptorHID(sup)
return dcdStageSetup
default:
// Unhandled device class
}
// GET CONFIGURATION (0x08):
case descRequestStandardGetConfiguration:
@@ -247,8 +269,38 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// GET DESCRIPTOR (0x06):
case descRequestStandardGetDescriptor:
d.controlDescriptor(sup)
return dcdStageSetup
// Respond based on our device class configuration
switch d.cc.id {
// CDC-ACM (single)
case classDeviceCDCACM:
d.controlDescriptorCDCACM(sup)
return dcdStageSetup
// HID
case classDeviceHID:
d.controlDescriptorHID(sup)
return dcdStageSetup
default:
// Unhandled device class
}
// GET DESCRIPTOR (0x06):
case descHIDRequestGetReport:
// Respond based on our device class configuration
switch d.cc.id {
// HID
case classDeviceHID:
d.controlDescriptorHID(sup)
return dcdStageSetup
default:
// Unhandled device class
}
default:
// Unhandled request
@@ -262,11 +314,15 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// CLEAR FEATURE (0x01):
case descRequestStandardClearFeature:
// TODO
d.endpointClearFeature(uint8(sup.wIndex))
d.controlReceive(uintptr(0), 0, false)
return dcdStageSetup
// SET FEATURE (0x03):
case descRequestStandardSetFeature:
// TODO
d.endpointSetFeature(uint8(sup.wIndex))
d.controlReceive(uintptr(0), 0, false)
return dcdStageSetup
default:
// Unhandled request
@@ -322,6 +378,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
d.controlReceive(
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
descCDCACMCodingSize, true)
// CDC Line Coding packet receipt handling occurs in method
// controlComplete().
return dcdStageSetup
}
@@ -338,11 +396,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// CDC-ACM (single)
case classDeviceCDCACM:
// Determine interface destination of the notification
// Determine interface destination of the request
switch sup.wIndex {
// Control/status interface:
case descCDCACMInterfaceCtrl:
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
d.uartSetLineState(0 != sup.wValue&0x01, 0 != sup.wValue&0x02)
d.controlReceive(uintptr(0), 0, false)
return dcdStageSetup
@@ -369,6 +429,79 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// Unhandled device class
}
// HID | SET REPORT (0x09)
case descHIDRequestSetReport:
// Respond based on our device class configuration
switch d.cc.id {
// HID
case classDeviceHID:
if sup.wLength <= descHIDCxCount {
d.setup = sup
descHID[d.cc.config-1].cx[0] = 0xE9
d.controlReceive(
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
uint32(sup.wLength), true)
return dcdStageSetup
}
default:
// Unhandled device class
}
// HID | SET IDLE (0x0A)
case descHIDRequestSetIdle:
// Respond based on our device class configuration
switch d.cc.id {
// HID
case classDeviceHID:
idleRate := sup.wValue >> 8
// TBD: do we need to handle this request? wIndex contains the target
// interface of the request.
_ = idleRate
d.controlReceive(uintptr(0), 0, false)
return dcdStageSetup
default:
// Unhandled device class
}
default:
// Unhandled request
}
// --- INTERFACE Tx (IN) ---
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
// Identify which request was received
switch sup.bRequest {
// HID | GET REPORT (0x01)
case descHIDRequestGetReport:
// Respond based on our device class configuration
switch d.cc.id {
// HID
case classDeviceHID:
reportType := uint8(sup.wValue >> 8)
reportID := uint8(sup.wValue)
// TBD: do we need to handle this request? wIndex contains the target
// interface of the request.
_, _ = reportType, reportID
d.controlReply[0] = 0
d.controlReply[1] = 0
d.controlTransmit(
uintptr(unsafe.Pointer(&d.controlReply[0])), 2, false)
return dcdStageSetup
default:
// Unhandled device class
}
default:
// Unhandled request
}
@@ -419,15 +552,14 @@ func (d *dcd) controlComplete(status uint32) {
case classDeviceCDCACM:
acm := &descCDCACM[d.cc.config-1]
// Determine interface destination of the notification
// Determine interface destination of the request
switch d.setup.wIndex {
// Control/status interface:
// CDC-ACM Control Interface:
case descCDCACMInterfaceCtrl:
// Notify PHY to handle triggers like special baud rates, which
// signal to reboot into bootloader or begin receiving OTA updates
d.controlLineCoding(descCDCACMLineCoding{
d.uartSetLineCoding(descCDCACMLineCoding{
baud: packU32(acm.cx[:]),
stopBits: acm.cx[4],
parity: acm.cx[5],
@@ -442,6 +574,60 @@ func (d *dcd) controlComplete(status uint32) {
// Unhandled device class
}
// HID | SET REPORT (0x09)
case descHIDRequestSetReport:
// Respond based on our device class configuration
switch d.cc.id {
// HID
case classDeviceHID:
hid := &descHID[d.cc.config-1]
// Determine interface destination of the request
switch d.setup.wIndex {
// HID Keyboard Interface
case descHIDInterfaceKeyboard:
// Determine the type of descriptor being requested
switch d.setup.wValue >> 8 {
// Configuration descriptor
case descTypeConfigure:
if 1 == d.setup.wLength {
hid.keyboard.led = hid.cx[0]
d.controlTransmit(uintptr(0), 0, false)
}
default:
// Unhandled descriptor type
}
// HID Serial Interface
case descHIDInterfaceSerial:
// Determine the type of descriptor being requested
switch d.setup.wValue >> 8 {
// String descriptor
case descTypeString:
if d.setup.wLength >= 4 && 0x68C245A9 == packU32(hid.cx[0:4]) {
d.enableSOF(true, descHIDInterfaceCount)
}
default:
// Unhandled descriptor type
}
default:
// Unhandled device interface
}
default:
// Unhandled device class
}
default:
// Unhandled request
}
@@ -455,129 +641,295 @@ func (d *dcd) controlComplete(status uint32) {
}
}
func (d *dcd) controlDescriptor(sup dcdSetup) {
func (d *dcd) controlDescriptorCDCACM(sup dcdSetup) {
// Respond based on our device class configuration
switch d.cc.id {
acm := &descCDCACM[d.cc.config-1]
dxn := uint8(0)
// CDC-ACM (single)
case classDeviceCDCACM:
acm := &descCDCACM[d.cc.config-1]
dxn := uint8(0)
// Determine the type of descriptor being requested
switch sup.wValue >> 8 {
// Determine the type of descriptor being requested
switch sup.wValue >> 8 {
// Device descriptor
case descTypeDevice:
dxn = descLengthDevice
_ = copy(acm.dx[:], acm.device[:dxn])
// Device descriptor
case descTypeDevice:
dxn = descLengthDevice
_ = copy(acm.dx[:], acm.device[:dxn])
// Configuration descriptor
case descTypeConfigure:
dxn = uint8(descCDCACMConfigSize)
_ = copy(acm.dx[:], acm.config[:dxn])
// Configuration descriptor
case descTypeConfigure:
dxn = uint8(descCDCACMConfigSize)
_ = copy(acm.dx[:], acm.config[:dxn])
// String descriptor
case descTypeString:
if 0 == len(acm.locale) {
break // No string descriptors defined!
}
var sd []uint8
if 0 == uint8(sup.wValue) {
// String descriptor
case descTypeString:
if 0 == len(acm.locale) {
break // No string descriptors defined!
// setup.wIndex contains an arbitrary index referring to a collection of
// strings in some given language. This case (setup.wValue = [0x03]00)
// is a string request from the host to determine what that language is.
//
// In subsequent string requests, the host will populate setup.wIndex
// with the language code we return here in this string descriptor.
//
// This way all strings returned to the host are in the same language,
// whatever language that may be.
code := int(sup.wIndex)
if code >= len(acm.locale) {
code = 0
}
var sd []uint8
if 0 == uint8(sup.wValue) {
sd = acm.locale[code].descriptor[sup.wValue&0xFF][:]
// setup.wIndex contains an arbitrary index referring to a collection of
// strings in some given language. This case (setup.wValue = [0x03]00)
// is a string request from the host to determine what that language is.
//
// In subsequent string requests, the host will populate setup.wIndex
// with the language code we return here in this string descriptor.
//
// This way all strings returned to the host are in the same language,
// whatever language that may be.
code := int(sup.wIndex)
if code >= len(acm.locale) {
code = 0
}
sd = acm.locale[code].descriptor[sup.wValue&0xFF][:]
} else {
} else {
// setup.wIndex now contains a language code, which we specified in a
// previous request (above: setup.wValue = [0x03]00). We need to locate
// the set of strings whose language matches the language code given in
// this new setup.wIndex.
for code := range acm.locale {
if sup.wIndex == acm.locale[code].language {
// Found language, check if string descriptor at given index exists
if int(sup.wValue&0xFF) < len(acm.locale[code].descriptor) {
// setup.wIndex now contains a language code, which we specified in a
// previous request (above: setup.wValue = [0x03]00). We need to locate
// the set of strings whose language matches the language code given in
// this new setup.wIndex.
for code := range acm.locale {
if sup.wIndex == acm.locale[code].language {
// Found language, check if string descriptor at given index exists
if int(sup.wValue&0xFF) < len(acm.locale[code].descriptor) {
// Found language with a string defined at the requested index.
//
// TODO: Add API methods to device controller that allows the user
// to provide these strings at/before driver initialization.
//
// For now, we just always use the descCommon* strings.
var s string
switch uint8(sup.wValue) {
case 1:
s = descCommonManufacturer
case 2:
s = descCommonProduct
case 3:
s = descCommonSerialNumber
}
// Construct a string descriptor dynamically to be transmitted on
// the serial bus.
sd = acm.locale[code].descriptor[int(sup.wValue&0xFF)][:]
// String descriptor format is 2-byte header + 2-bytes per rune
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
sd[1] = descTypeString // header[1] = descriptor type
// Copy UTF-8 string into string descriptor as UTF-16
for n, c := range s {
if 2+2*n >= len(sd) {
break
}
sd[2+2*n] = uint8(c)
sd[3+2*n] = 0
}
break // end search for matching language code
// Found language with a string defined at the requested index.
//
// TODO: Add API methods to device controller that allows the user
// to provide these strings at/before driver initialization.
//
// For now, we just always use the descCommon* strings.
var s string
switch uint8(sup.wValue) {
case 1:
s = descCommonManufacturer
case 2:
s = descCommonProduct + " CDC-ACM"
case 3:
s = descCommonSerialNumber
}
// Construct a string descriptor dynamically to be transmitted on
// the serial bus.
sd = acm.locale[code].descriptor[int(sup.wValue&0xFF)][:]
// String descriptor format is 2-byte header + 2-bytes per rune
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
sd[1] = descTypeString // header[1] = descriptor type
// Copy UTF-8 string into string descriptor as UTF-16
for n, c := range s {
if 2+2*n >= len(sd) {
break
}
sd[2+2*n] = uint8(c)
sd[3+2*n] = 0
}
break // end search for matching language code
}
}
}
// Copy string descriptor into descriptor transmit buffer
if nil != sd && len(sd) >= 0 {
dxn = sd[0]
_ = copy(acm.dx[:], sd[:dxn])
}
// Device qualification descriptor
case descTypeQualification:
dxn = descLengthQualification
_ = copy(acm.dx[:], acm.qualif[:dxn])
// Alternate configuration descriptor
case descTypeOtherSpeedConfiguration:
// TODO
default:
// Unhandled descriptor type
}
// Copy string descriptor into descriptor transmit buffer
if nil != sd && len(sd) >= 0 {
dxn = sd[0]
_ = copy(acm.dx[:], sd[:dxn])
}
if dxn > 0 {
if dxn > uint8(sup.wLength) {
dxn = uint8(sup.wLength)
// Device qualification descriptor
case descTypeQualification:
dxn = descLengthQualification
_ = copy(acm.dx[:], acm.qualif[:dxn])
// Alternate configuration descriptor
case descTypeOtherSpeedConfiguration:
// TODO
default:
// Unhandled descriptor type
}
if dxn > 0 {
if dxn > uint8(sup.wLength) {
dxn = uint8(sup.wLength)
}
flushCache(
uintptr(unsafe.Pointer(&acm.dx[0])), uintptr(dxn))
d.controlTransmit(
uintptr(unsafe.Pointer(&acm.dx[0])), uint32(dxn), false)
}
}
func (d *dcd) controlDescriptorHID(sup dcdSetup) {
hid := &descHID[d.cc.config-1]
dxn := uint8(0)
pos := uint8(0)
// Determine the type of descriptor being requested
switch sup.wValue >> 8 {
// Device descriptor
case descTypeDevice:
dxn = descLengthDevice
_ = copy(hid.dx[:], hid.device[:dxn])
// Configuration descriptor
case descTypeConfigure:
dxn = uint8(descHIDConfigSize)
_ = copy(hid.dx[:], hid.config[:dxn])
// String descriptor
case descTypeString:
if 0 == len(hid.locale) {
break // No string descriptors defined!
}
var sd []uint8
if 0 == uint8(sup.wValue) {
// setup.wIndex contains an arbitrary index referring to a collection of
// strings in some given language. This case (setup.wValue = [0x03]00)
// is a string request from the host to determine what that language is.
//
// In subsequent string requests, the host will populate setup.wIndex
// with the language code we return here in this string descriptor.
//
// This way all strings returned to the host are in the same language,
// whatever language that may be.
code := int(sup.wIndex)
if code >= len(hid.locale) {
code = 0
}
flushCache(
uintptr(unsafe.Pointer(&acm.dx[0])), uintptr(dxn))
d.controlTransmit(
uintptr(unsafe.Pointer(&acm.dx[0])), uint32(dxn), false)
sd = hid.locale[code].descriptor[sup.wValue&0xFF][:]
} else {
// setup.wIndex now contains a language code, which we specified in a
// previous request (above: setup.wValue = [0x03]00). We need to locate
// the set of strings whose language matches the language code given in
// this new setup.wIndex.
for code := range hid.locale {
if sup.wIndex == hid.locale[code].language {
// Found language, check if string descriptor at given index exists
if int(sup.wValue&0xFF) < len(hid.locale[code].descriptor) {
// Found language with a string defined at the requested index.
//
// TODO: Add API methods to device controller that allows the user
// to provide these strings at/before driver initialization.
//
// For now, we just always use the descCommon* strings.
var s string
switch uint8(sup.wValue) {
case 1:
s = descCommonManufacturer
case 2:
s = descCommonProduct + " HID"
case 3:
s = descCommonSerialNumber
}
// Construct a string descriptor dynamically to be transmitted on
// the serial bus.
sd = hid.locale[code].descriptor[int(sup.wValue&0xFF)][:]
// String descriptor format is 2-byte header + 2-bytes per rune
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
sd[1] = descTypeString // header[1] = descriptor type
// Copy UTF-8 string into string descriptor as UTF-16
for n, c := range s {
if 2+2*n >= len(sd) {
break
}
sd[2+2*n] = uint8(c)
sd[3+2*n] = 0
}
break // end search for matching language code
}
}
}
}
// Copy string descriptor into descriptor transmit buffer
if nil != sd && len(sd) >= 0 {
dxn = sd[0]
_ = copy(hid.dx[:], sd[:dxn])
}
// Device qualification descriptor
case descTypeQualification:
dxn = descLengthQualification
_ = copy(hid.dx[:], hid.qualif[:dxn])
// Alternate configuration descriptor
case descTypeOtherSpeedConfiguration:
// TODO
// HID descriptor
case descTypeHID:
// Determine interface destination of the request
switch sup.wIndex {
case descHIDInterfaceKeyboard:
pos = descHIDConfigKeyboardPos
case descHIDInterfaceMouse:
pos = descHIDConfigMousePos
case descHIDInterfaceSerial:
pos = descHIDConfigSerialPos
case descHIDInterfaceJoystick:
pos = descHIDConfigJoystickPos
case descHIDInterfaceMediaKey:
pos = descHIDConfigMediaKeyPos
default:
// Unhandled HID interface
}
if 0 != pos {
dxn = descLengthInterface
_ = copy(hid.dx[:], hid.config[pos:pos+dxn])
}
// HID report descriptor
case descTypeHIDReport:
// Determine interface destination of the request
switch sup.wIndex {
case descHIDInterfaceKeyboard:
dxn = uint8(len(descHIDReportKeyboard))
_ = copy(hid.dx[:], descHIDReportKeyboard[:])
case descHIDInterfaceMouse:
dxn = uint8(len(descHIDReportMouse))
_ = copy(hid.dx[:], descHIDReportMouse[:])
case descHIDInterfaceSerial:
dxn = uint8(len(descHIDReportSerial))
_ = copy(hid.dx[:], descHIDReportSerial[:])
case descHIDInterfaceJoystick:
dxn = uint8(len(descHIDReportJoystick))
_ = copy(hid.dx[:], descHIDReportJoystick[:])
case descHIDInterfaceMediaKey:
dxn = uint8(len(descHIDReportMediaKey))
_ = copy(hid.dx[:], descHIDReportMediaKey[:])
default:
// Unhandled HID interface
}
default:
// Unhandled device class
// Unhandled descriptor type
}
if dxn > 0 {
if dxn > uint8(sup.wLength) {
dxn = uint8(sup.wLength)
}
flushCache(
uintptr(unsafe.Pointer(&hid.dx[0])), uintptr(dxn))
d.controlTransmit(
uintptr(unsafe.Pointer(&hid.dx[0])), uint32(dxn), false)
}
}
+662 -179
View File
@@ -304,152 +304,75 @@ const (
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
)
// 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(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
lsU8(descCommonReleaseID), // Device release number in BCD (low)
msU8(descCommonReleaseID), // 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
}
// USB HID constants defined per specification
const (
// HID class
descHIDType = 0x03
// 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
}
// HID subclass
descHIDSubNone = 0x00
descHIDSubBoot = 0x01
// HID protocol
descHIDProtoNone = 0x00
descHIDProtoKeyboard = 0x01
descHIDProtoMouse = 0x02
descHIDRequestGetReport = 0x01 // HID request GET_REPORT
descHIDRequestGetReportTypeInput = 0x01 // HID request GET_REPORT type INPUT
descHIDRequestGetReportTypeOutput = 0x02 // HID request GET_REPORT type OUTPUT
descHIDRequestGetReportTypeFeature = 0x03 // HID request GET_REPORT type FEATURE
descHIDRequestGetIdle = 0x02 // HID request GET_IDLE
descHIDRequestGetProtocol = 0x03 // HID request GET_PROTOCOL
descHIDRequestSetReport = 0x09 // HID request SET_REPORT
descHIDRequestSetIdle = 0x0A // HID request SET_IDLE
descHIDRequestSetProtocol = 0x0B // HID request SET_PROTOCOL
)
const (
// Size of all CDC-ACM configuration descriptors.
descCDCACMConfigSize = uint16(
descLengthConfigure + // configuration
descLengthInterface + // communication/control interface
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
descLengthEndpoint) // data output endpoint
descLengthConfigure + // Configuration Header
descLengthInterface + // CDC Interface Descriptor
descCDCFuncLengthHeader + // CDC Header
descCDCFuncLengthCallManagement + // CDC Call Management Func Descriptor
descCDCFuncLengthAbstractControl + // CDC Abstract Control Func Descriptor
descCDCFuncLengthUnion + // CDC Union Functional Descriptor
descLengthEndpoint + // CDC Status IN Endpoint Descriptor
descLengthInterface + // CDC Data Interface Descriptor
descLengthEndpoint + // CDC Data IN Endpoint Descriptor
descLengthEndpoint) // CDC Data OUT Endpoint Descriptor
// Size of all HID configuration descriptors.
descHIDConfigSize = uint16(
descLengthConfigure + // Configuration Header
descLengthInterface + // Keyboard Interface Descriptor
descLengthInterface + // Keyboard HID Interface Descriptor
descLengthEndpoint + // Keyboard Endpoint Descriptor
descLengthInterface + // Mouse Interface Descriptor
descLengthInterface + // Mouse HID Interface Descriptor
descLengthEndpoint + // Mouse Endpoint Descriptor
descLengthInterface + // Serial Interface Descriptor
descLengthInterface + // Serial HID Interface Descriptor
descLengthEndpoint + // Serial Endpoint Descriptor
descLengthEndpoint +
descLengthInterface + // Joystick Interface Descriptor
descLengthInterface + // Joystick HID Interface Descriptor
descLengthEndpoint + // Joystick Endpoint Descriptor
descLengthInterface + // Keyboard Media Keys Interface Descriptor
descLengthInterface + // Keyboard Media Keys HID Interface Descriptor
descLengthEndpoint) // Keyboard Media Keys Endpoint Descriptor
// Position of each HID interface descriptor as offsets into the configuration
// descriptor. See comments in the configuration descriptor definition for the
// incremental tally that computes these.
descHIDConfigKeyboardPos = 18
descHIDConfigMousePos = 43
descHIDConfigSerialPos = 68
descHIDConfigJoystickPos = 100
descHIDConfigMediaKeyPos = 125
)
// 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
descEndptConfigAttr, // 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
}
type (
// descString is the actual byte array used to hold string descriptors. The
// first two bytes are a USB-specified header (0=length, 1=type), and the
@@ -479,28 +402,6 @@ const (
// for each string) seems a good compromise.
)
// descCDCACM0String holds the default string descriptors for CDC-ACM[0], i.e.,
// configuration index 1.
var descCDCACM0String = [descCDCACMLanguageCount]descStringLanguage{
{ // [0x0409] US English
language: descLanguageEnglish,
descriptor: descStringIndex{
{ /* [0] Language */
4,
descTypeString,
lsU8(descLanguageEnglish),
msU8(descLanguageEnglish),
},
// Actual string descriptors (index > 0) are copied into here at runtime!
// This allows for application- or even user-defined string descriptors.
{ /* [1] Manufacturer */ },
{ /* [2] Product */ },
{ /* [3] Serial Number */ },
},
},
}
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
const descCDCACMCodingSize = 7
@@ -514,23 +415,19 @@ type descCDCACMLineCoding struct {
// Common configuration constants for the USB CDC-ACM (single) device class.
const (
// String descriptor languages available
descCDCACMLanguageCount = 1
descCDCACMLanguageCount = 1 // String descriptor languages available
// Interfaces for all CDC-ACM configurations.
descCDCACMInterfaceCount = 2
descCDCACMInterfaceCtrl = 0
descCDCACMInterfaceData = 1
descCDCACMInterfaceCount = 2 // Interfaces for all CDC-ACM configurations.
descCDCACMEndpointCount = 4 // Endpoints for all CDC-ACM configurations.
// 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.
descCDCACMInterfaceCtrl = 0 // CDC-ACM Control Interface
descCDCACMEndpointStatus = 2 // CDC-ACM Interrupt IN Endpoint
descCDCACMConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
descCDCACMInterfaceData = 1 // CDC-ACM Data Interface
descCDCACMEndpointDataRx = 3 // CDC-ACM Bulk Data OUT (Rx) Endpoint
descCDCACMConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
descCDCACMEndpointDataTx = 4 // CDC-ACM Bulk Data IN (Tx) Endpoint
descCDCACMConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
)
@@ -547,14 +444,600 @@ type descCDCACMClass struct {
// descCDCACM holds statically-allocated instances for each of the CDC-ACM
// (single) device class configurations, ordered by index (offset by -1).
var descCDCACM = [descCDCACMCount]descCDCACMClass{
var descCDCACM = [dcdCount]descCDCACMClass{
{ // CDC-ACM (single) class configuration index 1
descCDCACMClassData: &descCDCACMData[0],
locale: &descCDCACM0String,
device: &descCDCACM0Device,
qualif: &descCDCACM0Qualif,
config: &descCDCACM0Config,
locale: &[descCDCACMLanguageCount]descStringLanguage{
{ // [0x0409] US English
language: descLanguageEnglish,
descriptor: descStringIndex{
{ /* [0] Language */
4,
descTypeString,
lsU8(descLanguageEnglish),
msU8(descLanguageEnglish),
},
// Actual string descriptors (index > 0) are copied into here at runtime!
// This allows for application- or even user-defined string descriptors.
{ /* [1] Manufacturer */ },
{ /* [2] Product */ },
{ /* [3] Serial Number */ },
},
},
},
device: &[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)
0, // Class code (assigned by the USB-IF).
0, // Subclass code (assigned by the USB-IF).
0, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
lsU8(descCommonReleaseID), // Device release number in BCD (low)
msU8(descCommonReleaseID), // 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
},
qualif: &[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)
0, // Class code (assigned by the USB-IF).
0, // Subclass code (assigned by the USB-IF).
0, // 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
},
config: &[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
descEndptConfigAttr, // 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)
descCDCACMStatusInterval, // 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
},
},
}
// Common configuration constants for the USB HID device class.
const (
descHIDLanguageCount = 1 // String descriptor languages available
descHIDInterfaceCount = 5 // Interfaces for all HID configurations.
descHIDEndpointCount = 6 // Endpoints for all HID configurations.
descHIDInterfaceKeyboard = 0 // HID Keyboard Interface
descHIDEndpointKeyboard = 3 // HID Keyboard IN Endpoint
descHIDConfigAttrKeyboard = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
descHIDInterfaceMouse = 1 // HID Mouse Interface
descHIDEndpointMouse = 5 // HID Mouse IN Endpoint
descHIDConfigAttrMouse = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
descHIDInterfaceSerial = 2 // HID Serial (UART emulation) Interface
descHIDEndpointSerialRx = 2 // HID Serial OUT (Rx) Endpoint
descHIDEndpointSerialTx = 2 // HID Serial IN (Tx) Endpoint
descHIDConfigAttrSerial = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxInterrupt
descHIDInterfaceJoystick = 3 // HID Joystick Interface
descHIDEndpointJoystick = 6 // HID Joystick IN Endpoint
descHIDConfigAttrJoystick = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
descHIDInterfaceMediaKey = 4 // HID Keyboard Media Keys Interface
descHIDEndpointMediaKey = 4 // HID Keyboard Media Keys IN Endpoint
descHIDConfigAttrMediaKey = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
)
// descHIDClass holds references to all descriptors, buffers, and control
// structures for the USB HID device class.
type descHIDClass struct {
*descHIDClassData // Target-defined, class-specific data
locale *[descHIDLanguageCount]descStringLanguage // string descriptors
device *[descLengthDevice]uint8 // device descriptor
qualif *[descLengthQualification]uint8 // device qualification descriptor
config *[descHIDConfigSize]uint8 // configuration descriptor
}
// descHID holds statically-allocated instances for each of the HID device class
// configurations, ordered by index (offset by -1).
var descHID = [dcdCount]descHIDClass{
{ // HID class configuration index 1
descHIDClassData: &descHIDData[0],
locale: &[descHIDLanguageCount]descStringLanguage{
{ // [0x0409] US English
language: descLanguageEnglish,
descriptor: descStringIndex{
{ /* [0] Language */
4,
descTypeString,
lsU8(descLanguageEnglish),
msU8(descLanguageEnglish),
},
// Actual string descriptors (index > 0) are copied into here at runtime!
// This allows for application- or even user-defined string descriptors.
{ /* [1] Manufacturer */ },
{ /* [2] Product */ },
{ /* [3] Serial Number */ },
},
},
},
device: &[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)
0, // Class code (assigned by the USB-IF).
0, // Subclass code (assigned by the USB-IF).
0, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
lsU8(descCommonReleaseID), // Device release number in BCD (low)
msU8(descCommonReleaseID), // 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
descHIDCount, // Number of possible configurations
},
qualif: &[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)
0, // Class code (assigned by the USB-IF).
0, // Subclass code (assigned by the USB-IF).
0, // Protocol code (assigned by the USB-IF).
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
descHIDCount, // Number of possible configurations
0, // Reserved
},
config: &[descHIDConfigSize]uint8{
// [0+9]
descLengthConfigure, // Size of this descriptor in bytes
descTypeConfigure, // Descriptor Type
lsU8(descHIDConfigSize), // Total length of data returned for this configuration (low)
msU8(descHIDConfigSize), // Total length of data returned for this configuration (high)
descHIDInterfaceCount, // 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
descEndptConfigAttr, // Configuration attributes
descHIDMaxPower, // Max power consumption when fully-operational (2 mA units)
// [9+9] Keyboard Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descHIDInterfaceKeyboard, // Interface index
0, // Alternate setting
1, // Number of endpoints
descHIDType, // Class code (HID = 0x03)
descHIDSubBoot, // Subclass code (Boot = 0x01)
descHIDProtoKeyboard, // Protocol code (Keyboard = 0x01)
0, // Interface Description String Index
// [18+9] Keyboard HID Interface Descriptor
descLengthInterface, // Descriptor length
descTypeHID, // Descriptor type
0x11, // HID BCD (low)
0x01, // HID BCD (high)
0, // Country code
1, // Number of descriptors
descTypeHIDReport, // Descriptor type
lsU8(uint16(len(descHIDReportKeyboard))), // Descriptor length (low)
msU8(uint16(len(descHIDReportKeyboard))), // Descriptor length (high)
// [27+7] Keyboard Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointKeyboard | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDKeyboardTxPacketSize), // Max packet size (low)
msU8(descHIDKeyboardTxPacketSize), // Max packet size (high)
descHIDKeyboardTxInterval, // Polling Interval
// [34+9] Mouse Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descHIDInterfaceMouse, // Interface index
0, // Alternate setting
1, // Number of endpoints
descHIDType, // Class code (HID = 0x03)
descHIDSubBoot, // Subclass code (Boot = 0x01)
descHIDProtoMouse, // Protocol code (Mouse = 0x02)
0, // Interface Description String Index
// [43+9] Mouse HID Interface Descriptor
descLengthInterface, // Descriptor length
descTypeHID, // Descriptor type
0x11, // HID BCD (low)
0x01, // HID BCD (high)
0, // Country code
1, // Number of descriptors
descTypeHIDReport, // Descriptor type
lsU8(uint16(len(descHIDReportMouse))), // Descriptor length (low)
msU8(uint16(len(descHIDReportMouse))), // Descriptor length (high)
// [52+7] Mouse Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointMouse | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDMouseTxPacketSize), // Max packet size (low)
msU8(descHIDMouseTxPacketSize), // Max packet size (high)
descHIDMouseTxInterval, // Polling Interval
// [59+9] Serial Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descHIDInterfaceSerial, // Interface index
0, // Alternate setting
2, // Number of endpoints
descHIDType, // Class code (HID = 0x03)
descHIDSubNone, // Subclass code
descHIDProtoNone, // Protocol code
0, // Interface Description String Index
// [68+9] Serial HID Interface Descriptor
descLengthInterface, // Descriptor length
descTypeHID, // Descriptor type
0x11, // HID BCD (low)
0x01, // HID BCD (high)
0, // Country code
1, // Number of descriptors
descTypeHIDReport, // Descriptor type
lsU8(uint16(len(descHIDReportSerial))), // Descriptor length (low)
msU8(uint16(len(descHIDReportSerial))), // Descriptor length (high)
// [77+7] Serial Tx Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointSerialTx | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDSerialTxPacketSize), // Max packet size (low)
msU8(descHIDSerialTxPacketSize), // Max packet size (high)
descHIDSerialTxInterval, // Polling Interval
// [84+7] Serial Rx Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointSerialRx | // Endpoint address
descEndptAddrDirectionOut,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDSerialRxPacketSize), // Max packet size (low)
msU8(descHIDSerialRxPacketSize), // Max packet size (high)
descHIDSerialRxInterval, // Polling Interval
// [91+9] Joystick Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descHIDInterfaceJoystick, // Interface index
0, // Alternate setting
1, // Number of endpoints
descHIDType, // Class code (HID = 0x03)
descHIDSubNone, // Subclass code
descHIDProtoNone, // Protocol code
0, // Interface Description String Index
// [100+9] Joystick HID Interface Descriptor
descLengthInterface, // Descriptor length
descTypeHID, // Descriptor type
0x11, // HID BCD (low)
0x01, // HID BCD (high)
0, // Country code
1, // Number of descriptors
descTypeHIDReport, // Descriptor type
lsU8(uint16(len(descHIDReportJoystick))), // Descriptor length (low)
msU8(uint16(len(descHIDReportJoystick))), // Descriptor length (high)
// [109+7] Joystick Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointJoystick | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDJoystickTxPacketSize), // Max packet size (low)
msU8(descHIDJoystickTxPacketSize), // Max packet size (high)
descHIDJoystickTxInterval, // Polling Interval
// [116+9] Keyboard Media Keys Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descHIDInterfaceMediaKey, // Interface index
0, // Alternate setting
1, // Number of endpoints
descHIDType, // Class code (HID = 0x03)
descHIDSubNone, // Subclass code
descHIDProtoNone, // Protocol code
0, // Interface Description String Index
// [125+9] Keyboard Media Keys HID Interface Descriptor
descLengthInterface, // Descriptor length
descTypeHID, // Descriptor type
0x11, // HID BCD (low)
0x01, // HID BCD (high)
0, // Country code
1, // Number of descriptors
descTypeHIDReport, // Descriptor type
lsU8(uint16(len(descHIDReportMediaKey))), // Descriptor length (low)
msU8(uint16(len(descHIDReportMediaKey))), // Descriptor length (high)
// [134+7] Keyboard Media Keys Endpoint Descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descHIDEndpointMediaKey | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descHIDMediaKeyTxPacketSize), // Max packet size (low)
msU8(descHIDMediaKeyTxPacketSize), // Max packet size (high)
descHIDMediaKeyTxInterval, // Polling Interval
},
},
}
var descHIDReportSerial = [...]uint8{
0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
0x09, 0x04, // Usage 0x04
0xA1, 0x5C, // Collection 0x5C
0x75, 0x08, // report size = 8 bits (global)
0x15, 0x00, // logical minimum = 0 (global)
0x26, 0xFF, 0x00, // logical maximum = 255 (global)
0x95, descHIDSerialTxPacketSize, // report count (global)
0x09, 0x75, // usage (local)
0x81, 0x02, // Input
0x95, descHIDSerialRxPacketSize, // report count (global)
0x09, 0x76, // usage (local)
0x91, 0x02, // Output
0x95, 0x04, // report count (global)
0x09, 0x76, // usage (local)
0xB1, 0x02, // Feature
0xC0, // end collection
}
var descHIDReportKeyboard = [...]uint8{
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ; Modifier keys
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x03, // Input (Constant), ; Reserved byte
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ; LED report
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ; LED report padding
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x7F, // Logical Maximum(104),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x7F, // Usage Maximum (104),
0x81, 0x00, // Input (Data, Array), ; Normal keys
0xC0, // End Collection
}
var descHIDReportMediaKey = [...]uint8{
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Controls)
0xA1, 0x01, // Collection (Application)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x19, 0x00, // Usage Minimum (0)
0x2A, 0x9C, 0x02, // Usage Maximum (0x29C)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x9C, 0x02, // Logical Maximum (0x29C)
0x81, 0x00, // Input (Data, Array)
0x05, 0x01, // Usage Page (Generic Desktop)
0x75, 0x08, // Report Size (8)
0x95, 0x03, // Report Count (3)
0x19, 0x00, // Usage Minimum (0)
0x29, 0xB7, // Usage Maximum (0xB7)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xB7, 0x00, // Logical Maximum (0xB7)
0x81, 0x00, // Input (Data, Array)
0xC0, // End Collection
}
var descHIDReportMouse = [...]uint8{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // REPORT_ID (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x08, // Usage Maximum (Button #8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x08, // Report Count (8)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8),
0x95, 0x03, // Report Count (3),
0x81, 0x06, // Input (Data, Variable, Relative)
0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8),
0x95, 0x01, // Report Count (1),
0x81, 0x06, // Input (Data, Variable, Relative)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // REPORT_ID (2)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16),
0x95, 0x02, // Report Count (2),
0x81, 0x02, // Input (Data, Variable, Absolute)
0xC0, // End Collection
}
var descHIDReportJoystick = [...]uint8{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x02, // Report Count (2)
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
}
+481 -75
View File
@@ -5,6 +5,14 @@ package usb
// descCPUFrequencyHz defines the target CPU frequency (Hz).
const descCPUFrequencyHz = 600000000
// descCDCACMCount defines the number of USB cores that may be configured as
// CDC-ACM (single) devices.
const descCDCACMCount = 0
// descHIDCount defines the number of USB cores that may be configured as a
// composite (keyboard + mouse + joystick) human interface device (HID).
const descHIDCount = 1
// General USB device identification constants.
const (
descCommonVendorID = 0x16C0
@@ -12,39 +20,166 @@ const (
descCommonReleaseID = 0x0101 // BCD (1.1)
descCommonLanguage = descLanguageEnglish
descCommonManufacturer = "NXP Semiconductors"
descCommonProduct = "TinyGo USB"
descCommonSerialNumber = "1"
descCommonManufacturer = "TinyGo"
descCommonProduct = "USB"
descCommonSerialNumber = "00000"
)
// Constants for USB CDC-ACM device classes.
const (
// descCDCACMCount defines the number of USB cores that will be configured as
// CDC-ACM (single) devices.
descCDCACMCount = 1
descCDCACMMaxPower = 50 // 100 mA
// CDC-ACM Control Buffers
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
descCDCACMRDCount = 2 * descCDCACMEndpointCount
descCDCACMTDCount = descCDCACMEndpointCount
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
descCDCACMCxCount = 8
descCDCACMMaxPower = 50 // 100 mA
// CDC-ACM Data Buffers
descCDCACMRDCount = 2 * descCDCACMEndpointCount
descCDCACMRxSize = descCDCACMDataRxPacketSize
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
descCDCACMTDCount = descCDCACMEndpointCount
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
descCDCACMTxTimeoutMs = 120 // millisec
descCDCACMTxSyncUs = 75 // microsec
descCDCACMStatusPacketSize = 16
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // high-speed
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // high-speed
descCDCACMRxSize = descCDCACMDataRxPacketSize
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
// Default CDC-ACM Endpoint Configurations (High-Speed)
descCDCACMDataRxFSPacketSize = 64 // full-speed
descCDCACMDataTxFSPacketSize = 64 // full-speed
descCDCACMDataRxHSPacketSize = 512 // high-speed
descCDCACMDataTxHSPacketSize = 512 // high-speed
descCDCACMStatusInterval = descCDCACMStatusHSInterval // Status
descCDCACMStatusPacketSize = descCDCACMStatusHSPacketSize //
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // Data Rx
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // Data Tx
// CDC-ACM Endpoint Configurations for Full-Speed Device
descCDCACMStatusFSInterval = 5 // Status
descCDCACMStatusFSPacketSize = 16 // (full-speed)
descCDCACMDataRxFSPacketSize = 64 // Data Rx (full-speed)
descCDCACMDataTxFSPacketSize = 64 // Data Tx (full-speed)
// CDC-ACM Endpoint Configurations for High-Speed Device
descCDCACMStatusHSInterval = 5 // Status
descCDCACMStatusHSPacketSize = 16 // (high-speed)
descCDCACMDataRxHSPacketSize = 512 // Data Rx (high-speed)
descCDCACMDataTxHSPacketSize = 512 // Data Tx (high-speed)
)
// Constants for USB HID (keyboard, mouse, joystick) device classes.
const (
descHIDMaxPower = 50 // 100 mA
// HID Control Buffers
descHIDQHCount = 2 * (descHIDEndpointCount + 1)
descHIDCxCount = 8
// HID Serial Buffers
descHIDSerialRDCount = 8
descHIDSerialRxSize = descHIDSerialRxPacketSize
descHIDSerialRxCount = descHIDSerialRxSize * descHIDSerialRDCount
descHIDSerialTDCount = 12
descHIDSerialTxSize = descHIDSerialTxPacketSize
descHIDSerialTxCount = descHIDSerialTxSize * descHIDSerialTDCount
descHIDSerialTxTimeoutMs = 50 // millisec
descHIDSerialTxSyncUs = 75 // microsec
// HID Keyboard Buffers
descHIDKeyboardTDCount = 12
descHIDKeyboardTxSize = 4 * descHIDKeyboardTxPacketSize
descHIDKeyboardTxCount = descHIDKeyboardTxSize * descHIDKeyboardTDCount
descHIDKeyboardTxTimeoutMs = 50 // millisec
// HID Mouse Buffers
descHIDMouseTDCount = 4
descHIDMouseTxSize = 4 * descHIDMouseTxPacketSize
descHIDMouseTxCount = descHIDMouseTxSize * descHIDMouseTDCount
descHIDMouseTxTimeoutMs = 30 // millisec
// HID Joystick Buffers
descHIDJoystickTDCount = 4
descHIDJoystickTxSize = 4 * descHIDJoystickTxPacketSize
descHIDJoystickTxCount = descHIDJoystickTxSize * descHIDJoystickTDCount
descHIDJoystickTxTimeoutMs = 30 // millisec
// Default HID Endpoint Configurations (High-Speed)
descHIDSerialRxInterval = descHIDSerialRxHSInterval // Serial Rx
descHIDSerialRxPacketSize = descHIDSerialRxHSPacketSize //
descHIDSerialTxInterval = descHIDSerialTxHSInterval // Serial Tx
descHIDSerialTxPacketSize = descHIDSerialTxHSPacketSize //
descHIDKeyboardTxInterval = descHIDKeyboardTxHSInterval // Keyboard
descHIDKeyboardTxPacketSize = descHIDKeyboardTxHSPacketSize //
descHIDMediaKeyTxInterval = descHIDMediaKeyTxHSInterval // Keyboard Media Keys
descHIDMediaKeyTxPacketSize = descHIDMediaKeyTxHSPacketSize //
descHIDMouseTxInterval = descHIDMouseTxHSInterval // Mouse
descHIDMouseTxPacketSize = descHIDMouseTxHSPacketSize //
descHIDJoystickTxInterval = descHIDJoystickTxHSInterval // Joystick
descHIDJoystickTxPacketSize = descHIDJoystickTxHSPacketSize //
// HID Endpoint Configurations for Full-Speed Device
descHIDSerialRxFSInterval = 2 // Serial Rx
descHIDSerialRxFSPacketSize = 8 // (full-speed)
descHIDSerialTxFSInterval = 1 // Serial Tx
descHIDSerialTxFSPacketSize = 16 // (full-speed)
descHIDKeyboardTxFSInterval = 4 // Keyboard
descHIDKeyboardTxFSPacketSize = 8 // (full-speed)
descHIDMediaKeyTxFSInterval = 4 // Keyboard Media Keys
descHIDMediaKeyTxFSPacketSize = 8 // (full-speed)
descHIDMouseTxFSInterval = 4 // Mouse
descHIDMouseTxFSPacketSize = 8 // (full-speed)
descHIDJoystickTxFSInterval = 4 // Joystick
descHIDJoystickTxFSPacketSize = 12 // (full-speed)
// HID Endpoint Configurations for High-Speed Device
descHIDSerialRxHSInterval = 2 // Serial
descHIDSerialRxHSPacketSize = 32 // (high-speed)
descHIDSerialTxHSInterval = 1 // Serial Tx
descHIDSerialTxHSPacketSize = 64 // (high-speed)
descHIDKeyboardTxHSInterval = 1 // Keyboard
descHIDKeyboardTxHSPacketSize = 8 // (high-speed)
descHIDMediaKeyTxHSInterval = 4 // Keyboard Media Keys
descHIDMediaKeyTxHSPacketSize = 8 // (high-speed)
descHIDMouseTxHSInterval = 1 // Mouse
descHIDMouseTxHSPacketSize = 8 // (high-speed)
descHIDJoystickTxHSInterval = 2 // Joystick
descHIDJoystickTxHSPacketSize = 12 // (high-speed)
)
// descCDCACM0QH is an array of endpoint queue heads, which is where all
@@ -71,18 +206,28 @@ const (
//go:align 4096
var descCDCACM0QH [descCDCACMQHCount]dhwEndpoint
// 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).
// descCDCACM0CD is the transfer descriptor for 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 dhwTransfer
// 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
// 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 dhwTransfer
// descCDCACM0Dx 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 descCDCACM0Dx [descCDCACMConfigSize]uint8
// 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
@@ -90,6 +235,11 @@ var descCDCACM0AD dhwTransfer
//go:align 32
var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
// descCDCACM0Rx is the receive (Rx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDCACM0Rx [descCDCACMRxCount]uint8
// 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)
@@ -97,36 +247,16 @@ var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
//go:align 32
var descCDCACM0TD [descCDCACMTDCount]dhwTransfer
// descCDCACM0LineCoding holds the emulated UART line coding for the default
// CDC-ACM (single) device class configuration (index 1).
// i.e., configuration index 1.
//go:align 32
var descCDCACM0LC descCDCACMLineCoding
// 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).
// descCDCACM0Tx is the transmit (Tx) transfer buffer 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
var descCDCACM0RDQue [(descCDCACMRDCount + 1)]uint16
// descCDCACM holds the buffers and control states for all of the CDC-ACM
// descCDCACMClassData holds the buffers and control states for all CDC-ACM
// (single) device class configurations, ordered by index (offset by -1), for
// iMXRT1062 targets only.
//
@@ -134,21 +264,30 @@ var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
// of the common/target-agnostic CDC-ACM class configurations (descCDCACM).
// 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 an additional hardware abstraction layer.
// Thus, this type functions as a hardware abstraction layer (HAL).
type descCDCACMClassData struct {
// CDC-ACM Control Buffers
qh *[descCDCACMQHCount]dhwEndpoint // endpoint queue heads
cd *dhwTransfer // control endpoint 0 Rx/Tx data transfer descriptor
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
rd *[descCDCACMRDCount]dhwTransfer // bulk data endpoint Rx (OUT) transfer descriptors
td *[descCDCACMTDCount]dhwTransfer // bulk data endpoint Tx (IN) transfer descriptors
cd *dhwTransfer // control endpoint 0 Rx/Tx transfer descriptor
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
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
cxSize uint16
// CDC-ACM Data Buffers
rd *[descCDCACMRDCount]dhwTransfer // bulk data endpoint Rx (OUT) transfer descriptors
rx *[descCDCACMRxCount]uint8 // bulk data endpoint Rx (OUT) transfer buffer
td *[descCDCACMTDCount]dhwTransfer // bulk data endpoint Tx (IN) transfer descriptors
tx *[descCDCACMTxCount]uint8 // bulk data endpoint Tx (IN) transfer buffer
rxCount *[descCDCACMRDCount]uint16
rxIndex *[descCDCACMRDCount]uint16
rxQueue *[(descCDCACMRDCount + 1)]uint16
sxSize uint16
rxSize uint16
txSize uint16
@@ -159,40 +298,307 @@ type descCDCACMClassData struct {
rxHead uint8
rxTail uint8
rxFree uint16
rxCount *[descCDCACMRDCount]uint16
rxIndex *[descCDCACMRDCount]uint16
rxQueue *[descCDCACMRDCount + 1]uint16
_ [2]uint8
}
// descCDCACMData holds statically-allocated instances for each of the target-
// specific (iMXRT1062) 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 descCDCACM.
//go:align 32
var descCDCACMData = [descCDCACMCount]descCDCACMClassData{
//go:align 64
var descCDCACMData = [dcdCount]descCDCACMClassData{
{ // -- CDC-ACM (single) Class Configuration Index 1 --
// CDC-ACM Control Buffers
{ // CDC-ACM (single) class configuration index 1 data
qh: &descCDCACM0QH,
cd: &descCDCACM0CD,
ad: &descCDCACM0AD,
rd: &descCDCACM0RD,
td: &descCDCACM0TD,
cx: &descCDCACM0Cx,
rx: &descCDCACM0Rx,
tx: &descCDCACM0Tx,
ad: &descCDCACM0AD,
dx: &descCDCACM0Dx,
cxSize: descCDCACMStatusPacketSize,
rxSize: descCDCACMDataRxPacketSize,
txSize: descCDCACMDataTxPacketSize,
// CDC-ACM Data Buffers
rd: &descCDCACM0RD,
rx: &descCDCACM0Rx,
td: &descCDCACM0TD,
tx: &descCDCACM0Tx,
rxCount: &descCDCACM0RDNum,
rxIndex: &descCDCACM0RDIdx,
rxQueue: &descCDCACM0RDQue,
sxSize: descCDCACMStatusPacketSize,
rxSize: descCDCACMDataRxPacketSize,
txSize: descCDCACMDataTxPacketSize,
},
}
// descHID0QH is an array of endpoint queue heads, which is where all transfers
// for a given endpoint are managed, for the default HID 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 descHID0QH [descHIDQHCount]dhwEndpoint
// descHID0CD is the transfer descriptor for messages transmitted or received on
// the status/control endpoint 0 for the default HID device class configuration
// (index 1).
//go:align 32
var descHID0CD dhwTransfer
// descHID0Cx is the buffer for control/status data received on endpoint 0 of
// the default HID device class configuration (index 1).
//go:align 32
var descHID0Cx [descHIDCxCount]uint8
// descHID0AD is the transfer descriptor for ackowledgement (ACK) messages
// transmitted or received on the status/control endpoint 0 for the default HID
// device class configuration (index 1).
//go:align 32
var descHID0AD dhwTransfer
// descHID0Dx is the transmit (Tx) buffer of descriptor data on endpoint 0 for
// the default HID device class configuration (index 1).
//go:align 32
var descHID0Dx [descHIDConfigSize]uint8
// descHID0SerialRD is an array of transfer descriptors for serial Rx (OUT)
// transfers, which describe to the device controller the location and quantity
// of data being received for a given transfer, for the default HID device class
// configuration (index 1).
//go:align 32
var descHID0SerialRD [descHIDSerialRDCount]dhwTransfer
// descHID0SerialRx is the serial receive (Rx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
var descHID0SerialRx [descHIDSerialRxCount]uint8
// descHID0SerialTD is an array of transfer descriptors for serial Tx (IN)
// transfers, which describe to the device controller the location and quantity
// of data being transmitted for a given transfer, for the default HID device
// class configuration (index 1).
//go:align 32
var descHID0SerialTD [descHIDSerialTDCount]dhwTransfer
// descHID0SerialTx is the serial transmit (Tx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
var descHID0SerialTx [descHIDSerialTxCount]uint8
var descHID0SerialRDIdx [descHIDSerialRDCount]uint16
var descHID0SerialRDQue [(descHIDSerialRDCount + 1)]uint16
// descHID0KeyboardTD is an array of transfer descriptors for keyboard Tx (IN)
// transfers, which describe to the device controller the location and quantity
// of data being transmitted for a given transfer, for the default HID device
// class configuration (index 1).
//go:align 32
var descHID0KeyboardTD [descHIDKeyboardTDCount]dhwTransfer
// descHID0KeyboardTx is the keyboard transmit (Tx) transfer buffer for the
// default HID device class configuration (index 1).
//go:align 32
var descHID0KeyboardTx [descHIDKeyboardTxCount]uint8
// descHID0KeyboardTp is the keyboard HID report transmit (Tx) transfer buffer
// for the default HID device class configuration (index 1).
//go:align 32
var descHID0KeyboardTp [descHIDKeyboardTxPacketSize]uint8
//go:align 32
var descHID0KeyboardTxKey [hidKeyboardKeyCount]uint8
//go:align 32
var descHID0KeyboardTxCon [hidKeyboardConCount]uint16
//go:align 32
var descHID0KeyboardTxSys [hidKeyboardSysCount]uint8
// descHID0MouseTD is an array of transfer descriptors for mouse Tx (IN)
// transfers, which describe to the device controller the location and quantity
// of data being transmitted for a given transfer, for the default HID device
// class configuration (index 1).
//go:align 32
var descHID0MouseTD [descHIDMouseTDCount]dhwTransfer
// descHID0MouseTx is the mouse transmit (Tx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
var descHID0MouseTx [descHIDMouseTxCount]uint8
// descHID0JoystickTD is an array of transfer descriptors for joystick Tx (IN)
// transfers, which describe to the device controller the location and quantity
// of data being transmitted for a given transfer, for the default HID device
// class configuration (index 1).
//go:align 32
var descHID0JoystickTD [descHIDJoystickTDCount]dhwTransfer
// descHID0JoystickTx is the joystick transmit (Tx) transfer buffer for the
// default HID device class configuration (index 1).
//go:align 32
var descHID0JoystickTx [descHIDJoystickTxCount]uint8
// descHID0Keyboard is the Keyboard instance with which the user may interact
// when using the default HID device class configuration (index 1).
//go:align 64
var descHID0Keyboard = Keyboard{
key: &descHID0KeyboardTxKey,
con: &descHID0KeyboardTxCon,
sys: &descHID0KeyboardTxSys,
}
// descHIDClassData holds the buffers and control states for all of the HID
// device class configurations, ordered by index (offset by -1), for iMXRT1062
// targets only.
//
// Instances of this type (elements of descHIDData) are embedded in elements
// of the common/target-agnostic HID class configurations (descHID).
// 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 descHIDClassData struct {
// HID Control Buffers
qh *[descHIDQHCount]dhwEndpoint // endpoint queue heads
cd *dhwTransfer // control endpoint 0 Rx/Tx transfer descriptor
cx *[descHIDCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
dx *[descHIDConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
// HID Serial Buffers
rdSerial *[descHIDSerialRDCount]dhwTransfer // interrupt endpoint serial Rx (OUT) transfer descriptors
rxSerial *[descHIDSerialRxCount]uint8 // interrupt endpoint serial Rx (OUT) transfer buffer
tdSerial *[descHIDSerialTDCount]dhwTransfer // interrupt endpoint serial Tx (IN) transfer descriptors
txSerial *[descHIDSerialTxCount]uint8 // interrupt endpoint serial Tx (IN) transfer buffer
rxSerialIndex *[descHIDSerialRDCount]uint16
rxSerialQueue *[(descHIDSerialRDCount + 1)]uint16
rxSerialSize uint16
txSerialSize uint16
txSerialHead uint8
txSerialFree uint16
txSerialPrev bool
rxSerialHead uint8
rxSerialTail uint8
rxSerialFree uint16
// HID Keyboard Buffers
tdKeyboard *[descHIDKeyboardTDCount]dhwTransfer // interrupt endpoint keyboard Tx (IN) transfer descriptors
txKeyboard *[descHIDKeyboardTxCount]uint8 // interrupt endpoint keyboard Tx (IN) transfer buffer
tpKeyboard *[descHIDKeyboardTxPacketSize]uint8 // interrupt endpoint keyboard Tx (IN) HID report bbuffer
txKeyboardSize uint16
txKeyboardHead uint8
txKeyboardPrev bool
// HID Mouse Buffers
tdMouse *[descHIDMouseTDCount]dhwTransfer // interrupt endpoint mouse Tx (IN) transfer descriptors
txMouse *[descHIDMouseTxCount]uint8 // interrupt endpoint mouse Tx (IN) transfer buffer
txMouseSize uint16
txMouseHead uint8
txMousePrev bool
// HID Joystick Buffers
tdJoystick *[descHIDJoystickTDCount]dhwTransfer // interrupt endpoint joystick Tx (IN) transfer descriptors
txJoystick *[descHIDJoystickTxCount]uint8 // interrupt endpoint joystick Tx (IN) transfer buffer
txJoystickSize uint16
txJoystickHead uint8
txJoystickPrev bool
// HID Device Instances
keyboard *Keyboard
}
// descHIDData holds statically-allocated instances for each of the target-
// specific (iMXRT1062) HID device class configurations' control and data
// structures, ordered by configuration index (offset by -1). Each element is
// embedded in a corresponding element of descHID.
//go:align 64
var descHIDData = [dcdCount]descHIDClassData{
{ // -- HID Class Configuration Index 1 --
// HID Control Buffers
qh: &descHID0QH,
cd: &descHID0CD,
cx: &descHID0Cx,
ad: &descHID0AD,
dx: &descHID0Dx,
// HID Serial Buffers
rdSerial: &descHID0SerialRD,
rxSerial: &descHID0SerialRx,
tdSerial: &descHID0SerialTD,
txSerial: &descHID0SerialTx,
rxSerialIndex: &descHID0SerialRDIdx,
rxSerialQueue: &descHID0SerialRDQue,
rxSerialSize: descHIDSerialRxPacketSize,
txSerialSize: descHIDSerialTxPacketSize,
// HID Keyboard Buffers
tdKeyboard: &descHID0KeyboardTD,
txKeyboard: &descHID0KeyboardTx,
tpKeyboard: &descHID0KeyboardTp,
txKeyboardSize: descHIDKeyboardTxPacketSize,
// HID Mouse Buffers
tdMouse: &descHID0MouseTD,
txMouse: &descHID0MouseTx,
txMouseSize: descHIDMouseTxPacketSize,
// HID Joystick Buffers
tdJoystick: &descHID0JoystickTD,
txJoystick: &descHID0JoystickTx,
txJoystickSize: descHIDJoystickTxPacketSize,
// HID Device Instances
keyboard: &descHID0Keyboard,
},
}
+383 -52
View File
@@ -40,6 +40,8 @@ type dhw struct {
sofUsage uint8
}
func runBootloader() { arm.Asm(`bkpt #251`) }
// cycleCount uses the ARM debug cycle counter available on iMXRT1062 (enabled
// in runtime_mimxrt1062_time.go) to return the number of CPU cycles since boot.
//go:inline
@@ -184,7 +186,9 @@ func (d *dhw) enableSOF(enable bool, iface uint8) {
d.bus.USBINTR.SetBits(nxp.USB_USBINTR_SRE)
}
arm.EnableInterrupts(ivm)
d.timerReboot = 80
} else {
d.timerReboot = 0
d.sofUsage &^= 1 << iface
if 0 == d.sofUsage {
d.bus.USBINTR.ClearBits(nxp.USB_USBINTR_SRE)
@@ -354,33 +358,23 @@ func (d *dhw) interrupt() {
d.timerReboot -= 1
if 0 == d.timerReboot {
d.enableSOF(false, descCDCACMInterfaceCount)
runBootloader()
}
}
}
}
func (d *dhw) controlBusSpeed() uint8 { return d.busSpeed }
func (d *dhw) speed() uint8 { return d.busSpeed }
func (d *dhw) controlDeviceAddress(addr uint16) {
func (d *dhw) setDeviceAddress(addr uint16) {
d.bus.DEVICEADDR.Set(nxp.USB_DEVICEADDR_USBADRA |
((uint32(addr) << nxp.USB_DEVICEADDR_USBADR_Pos) &
nxp.USB_DEVICEADDR_USBADR_Msk))
}
func (d *dhw) controlLineState(coding descCDCACMLineCoding, dtr, rts bool) {
// TBD: does the PHY need to handle on iMXRT1062 (e.g., Teensyduino Loader)?
}
func (d *dhw) controlLineCoding(coding descCDCACMLineCoding) {
if 134 == coding.baud {
d.enableSOF(true, descCDCACMInterfaceCount)
}
}
// controlStatus transitions transfers on control endpoint 0 into status stage.
func (d *dhw) controlStatus() {
// Not used on iMXRT1062
}
// =============================================================================
// Control Endpoint 0
// =============================================================================
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
// any other endpoint, use method endpointStall().
@@ -411,7 +405,7 @@ func (d *dhw) controlReceive(
} // wait for endpoint finish priming
}
ad.next = dhwTransferEOL
ad.token = 1 << 7
ad.token = 1 << 7 // Bit 7: active transfer
if notify {
ad.token |= 1 << 15
}
@@ -424,6 +418,8 @@ func (d *dhw) controlReceive(
if notify {
d.controlMask = tm
}
for 0 != d.bus.ENDPTPRIME.Get() {
} // wait for endpoint finish priming
}
// controlTransmit transmits (Tx, IN) data on control endpoint 0.
@@ -449,7 +445,7 @@ func (d *dhw) controlTransmit(
} // wait for endpoint finish priming
}
ad.next = dhwTransferEOL
ad.token = 1 << 7
ad.token = 1 << 7 // Bit 7: active transfer
if notify {
ad.token |= 1 << 15
}
@@ -462,11 +458,13 @@ func (d *dhw) controlTransmit(
if notify {
d.controlMask = rm
}
for 0 != d.bus.ENDPTPRIME.Get() {
} // wait for endpoint finish priming
}
// dhwEndpointSize defines the size (bytes) of a structure containing a USB
// standard endpoint.
const dhwEndpointSize = 64 // bytes
// =============================================================================
// Endpoint Descriptor
// =============================================================================
// dhwEndpoint defines a USB standard endpoint, used as the general channel of
// communication between host and device.
@@ -488,6 +486,10 @@ type dhwEndpoint struct {
callback func(transfer *dhwTransfer)
}
// dhwEndpointSize defines the size (bytes) of a structure containing a USB
// standard endpoint.
const dhwEndpointSize = 64 // bytes
// endpointQueueHead returns the queue head for the given endpoint address,
// encoded as direction D and endpoint number N with the 8-bit mask DxxxNNNN.
//go:inline
@@ -496,6 +498,8 @@ func (d *dhw) endpointQueueHead(endpoint uint8) *dhwEndpoint {
switch d.cc.id {
case classDeviceCDCACM:
return &descCDCACM[d.cc.config-1].qh[endpointIndex(endpoint)]
case classDeviceHID:
return &descHID[d.cc.config-1].qh[endpointIndex(endpoint)]
default:
return nil
}
@@ -552,17 +556,23 @@ func (d *dhw) endpointStall(endpoint uint8) {
)
}
// func (d *dhw) endpointPrime(mask uint32, transfer *dhwTransfer) {
// d.bus.ENDPTPRIME.Set(mask)
// }
func (d *dhw) endpointClearFeature(endpoint uint8) {
switch endpoint {
case rxEndpoint(endpoint):
d.endpointControlRegister(endpoint).ClearBits(nxp.USB_ENDPTCTRL0_RXS)
case txEndpoint(endpoint):
d.endpointControlRegister(endpoint).ClearBits(nxp.USB_ENDPTCTRL0_TXS)
}
}
// func (d *dhw) endpointPrimed() uint32 {
// return d.bus.ENDPTPRIME.Get()
// }
// func (d *dhw) endpointUnprime(mask uint32) {
// d.bus.ENDPTCOMPLETE.Set(mask)
// }
func (d *dhw) endpointSetFeature(endpoint uint8) {
switch endpoint {
case rxEndpoint(endpoint):
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_RXS)
case txEndpoint(endpoint):
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_TXS)
}
}
// endpointConfigure configures the given bulk data endpoint for transfer.
func (d *dhw) endpointConfigure(
@@ -603,8 +613,8 @@ func (d *dhw) endpointComplete(endpoint uint8) {
ep.first = nil
ep.last = nil
} else {
if 0 != t.token&(1<<7) {
// active transfer, new list begins here
if 0 != t.token&(1<<7) { // Bit 7: active transfer
// new list begins here
ep.first = t
break
} else {
@@ -634,15 +644,23 @@ func (d *dhw) endpointConfigureRx(
endpoint > descCDCACMEndpointCount {
return
}
ep := d.endpointQueueHead(rxEndpoint(endpoint))
d.endpointConfigure(ep, packetSize, zlp, callback)
if nil != callback {
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrRxPos
// HID
case classDeviceHID:
if endpoint < descHIDEndpointSerialRx ||
endpoint > descHIDEndpointCount {
return
}
default:
// Unhandled device class
}
ep := d.endpointQueueHead(rxEndpoint(endpoint))
d.endpointConfigure(ep, packetSize, zlp, callback)
if nil != callback {
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrRxPos
}
}
// endpointConfigureTx configures the given bulk data transmit (Tx, IN) endpoint
@@ -659,15 +677,23 @@ func (d *dhw) endpointConfigureTx(
endpoint > descCDCACMEndpointCount {
return
}
ep := d.endpointQueueHead(txEndpoint(endpoint))
d.endpointConfigure(ep, packetSize, zlp, callback)
if nil != callback {
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrTxPos
// HID
case classDeviceHID:
if endpoint < descHIDEndpointSerialRx ||
endpoint > descHIDEndpointCount {
return
}
default:
// Unhandled device class
}
ep := d.endpointQueueHead(txEndpoint(endpoint))
d.endpointConfigure(ep, packetSize, zlp, callback)
if nil != callback {
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrTxPos
}
}
// endpointReceive schedules a receive (Rx, OUT) transfer on the given endpoint.
@@ -682,13 +708,21 @@ func (d *dhw) endpointReceive(endpoint uint8, transfer *dhwTransfer) {
endpoint > descCDCACMEndpointCount {
return
}
ep := d.endpointQueueHead(rxEndpoint(endpoint))
em := (uint32(1) << endpoint) << descEndptConfigAttrRxPos
d.transferSchedule(ep, em, transfer)
// HID
case classDeviceHID:
if endpoint < descHIDEndpointSerialRx ||
endpoint > descHIDEndpointCount {
return
}
default:
// Unhandled device class
}
ep := d.endpointQueueHead(rxEndpoint(endpoint))
em := (uint32(1) << endpoint) << descEndptConfigAttrRxPos
d.transferSchedule(ep, em, transfer)
}
// endpointTransmit schedules a transmit (Tx, IN) transfer on the given
@@ -704,17 +738,26 @@ func (d *dhw) endpointTransmit(endpoint uint8, transfer *dhwTransfer) {
endpoint > descCDCACMEndpointCount {
return
}
ep := d.endpointQueueHead(txEndpoint(endpoint))
em := (uint32(1) << endpoint) << descEndptConfigAttrTxPos
d.transferSchedule(ep, em, transfer)
// HID
case classDeviceHID:
if endpoint < descHIDEndpointSerialRx ||
endpoint > descHIDEndpointCount {
return
}
default:
// Unhandled device class
}
ep := d.endpointQueueHead(txEndpoint(endpoint))
em := (uint32(1) << endpoint) << descEndptConfigAttrTxPos
d.transferSchedule(ep, em, transfer)
}
// dhwTransferSize defines the size (bytes) of a USB standard transfer packet.
const dhwTransferSize = 32 // bytes
// =============================================================================
// Transfer Descriptor
// =============================================================================
// dhwTransfer describes the size and location of data to be transferred to or
// from a USB endpoint.
@@ -725,6 +768,9 @@ type dhwTransfer struct {
param uint32
}
// dhwTransferSize defines the size (bytes) of a USB standard transfer packet.
const dhwTransferSize = 32 // bytes
// dhwTransferEOL is a sentinel value used to indicate the final node in a
// linked list of transfer descriptors.
var dhwTransferEOL = (*dhwTransfer)(unsafe.Pointer(uintptr(1)))
@@ -744,6 +790,8 @@ func (d *dhw) transferControl() (dat, ack *dhwTransfer) {
switch d.cc.id {
case classDeviceCDCACM:
return descCDCACM[d.cc.config-1].cd, descCDCACM[d.cc.config-1].ad
case classDeviceHID:
return descHID[d.cc.config-1].cd, descHID[d.cc.config-1].ad
default:
return nil, nil
}
@@ -753,7 +801,9 @@ func (d *dhw) transferPrepare(
transfer *dhwTransfer, data *uint8, size uint16, param uint32) {
transfer.next = dhwTransferEOL
transfer.token = (uint32(size) << 16) | (1 << 7)
// Set 15-bit packet size and transfer active bit 7.
transfer.token = (uint32(size&0x7FFF) << 16) | (1 << 7)
addr := uintptr(unsafe.Pointer(data))
for i := range transfer.pointer {
transfer.pointer[i] = addr + uintptr(i)*4096
@@ -794,6 +844,10 @@ endTransfer:
arm.EnableInterrupts(ivm)
}
// =============================================================================
// General-Purpose (GP) Timer
// =============================================================================
func (d *dhw) timerConfigure(timer int, usec uint32, fn func()) {
if timer < 0 || timer >= len(d.timerInterrupt) {
return
@@ -831,9 +885,15 @@ func (d *dhw) timerStop(timer int) {
}
}
// =============================================================================
// [CDC-ACM] Serial UART (Virtual COM Port)
// =============================================================================
func (d *dhw) uartConfigure() {
acm := &descCDCACM[d.cc.config-1]
switch d.controlBusSpeed() {
switch d.speed() {
case descDeviceSpeedHigh:
acm.rxSize = descCDCACMDataRxHSPacketSize
acm.txSize = descCDCACMDataTxHSPacketSize
@@ -843,6 +903,7 @@ func (d *dhw) uartConfigure() {
}
acm.txHead = 0
acm.txFree = 0
acm.txPrev = false
acm.rxHead = 0
acm.rxTail = 0
acm.rxFree = 0
@@ -855,7 +916,7 @@ func (d *dhw) uartConfigure() {
false, descCDCACMConfigAttrDataTx)
d.endpointConfigureTx(descCDCACMEndpointStatus,
acm.cxSize, false, nil)
acm.sxSize, false, nil)
d.endpointConfigureRx(descCDCACMEndpointDataRx,
acm.rxSize, false, d.uartNotify)
d.endpointConfigureTx(descCDCACMEndpointDataTx,
@@ -866,6 +927,16 @@ func (d *dhw) uartConfigure() {
d.timerConfigure(0, descCDCACMTxSyncUs, d.uartSync)
}
func (d *dhw) uartSetLineState(dtr, rts bool) {
// TBD: does the PHY need to handle on iMXRT1062 (e.g., Teensyduino Loader)?
}
func (d *dhw) uartSetLineCoding(coding descCDCACMLineCoding) {
if 134 == coding.baud {
d.enableSOF(true, descCDCACMInterfaceCount)
}
}
func (d *dhw) uartReceive(endpoint uint8) {
acm := &descCDCACM[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
@@ -1071,3 +1142,263 @@ func (d *dhw) uartSync() {
}
acm.txFree = 0
}
// =============================================================================
// [HID] Serial
// =============================================================================
func (d *dhw) serialConfigure() {
hid := &descHID[d.cc.config-1]
switch d.speed() {
case descDeviceSpeedHigh:
hid.rxSerialSize = descHIDSerialRxHSPacketSize
hid.txSerialSize = descHIDSerialTxHSPacketSize
default:
hid.rxSerialSize = descHIDSerialRxFSPacketSize
hid.txSerialSize = descHIDSerialTxFSPacketSize
}
// Rx and Tx are on same endpoint
d.endpointEnable(descHIDEndpointSerialRx,
false, descHIDConfigAttrSerial)
d.endpointConfigureRx(descHIDEndpointSerialRx,
hid.rxSerialSize, false, d.serialNotify)
d.endpointConfigureTx(descHIDEndpointSerialTx,
hid.txSerialSize, false, nil)
for i := range hid.rdSerial {
d.serialReceive(uint8(i))
}
d.timerConfigure(0, descHIDSerialTxSyncUs, d.serialSync)
}
func (d *dhw) serialReceive(endpoint uint8) {
hid := &descHID[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
buf := &hid.rxSerial[num*descHIDSerialRxSize]
d.enableInterrupts(false)
d.transferPrepare(&hid.rdSerial[num], buf, hid.rxSerialSize, uint32(endpoint))
deleteCache(uintptr(unsafe.Pointer(buf)), uintptr(hid.rxSerialSize))
d.endpointReceive(descHIDEndpointSerialRx, &hid.rdSerial[num])
d.enableInterrupts(true)
}
func (d *dhw) serialTransmit() {
hid := &descHID[d.cc.config-1]
xfer := &hid.tdSerial[hid.txSerialHead]
buff := &hid.txSerial[uint16(hid.txSerialHead)*descHIDSerialTxSize]
d.transferPrepare(xfer, buff, hid.txSerialSize, 0)
flushCache(uintptr(unsafe.Pointer(buff)), uintptr(hid.txSerialSize))
d.endpointTransmit(descHIDEndpointSerialTx, xfer)
hid.txSerialHead += 1
if hid.txSerialHead >= descHIDSerialTDCount {
hid.txSerialHead = 0
}
}
func (d *dhw) serialNotify(transfer *dhwTransfer) {
hid := &descHID[d.cc.config-1]
len := hid.rxSerialSize - (uint16(transfer.token>>16) & 0x7FFF)
p := transfer.param
if len == hid.rxSerialSize && 0 != hid.rxSerial[p*uint32(hid.rxSerialSize)] {
// data packet
hid.rxSerialIndex[p] = 0
h := hid.rxSerialHead + 1
if h > descHIDSerialRDCount { // should be >=
h = 0
}
hid.rxSerialQueue[h] = uint16(p)
hid.rxSerialHead = h
hid.rxSerialFree += len
} else {
// short packet
d.serialReceive(uint8(p))
}
}
// serialFlush discards all buffered input (Rx) data.
func (d *dhw) serialFlush() {
hid := &descHID[d.cc.config-1]
tail := hid.rxSerialTail
for tail != hid.rxSerialHead {
tail += 1
if tail > descHIDSerialRDCount {
tail = 0
}
i := hid.rxSerialQueue[tail]
d.serialReceive(uint8(i))
hid.rxSerialTail = tail
}
}
func (d *dhw) serialSync() {
const autoFlushTx = true
if !autoFlushTx {
return
}
hid := &descHID[d.cc.config-1]
if 0 == hid.txSerialFree {
return
}
xfer := &hid.tdSerial[hid.txSerialHead]
buff := &hid.txSerial[uint16(hid.txSerialHead)*descHIDSerialTxSize]
size := descHIDSerialTxSize - hid.txSerialFree
d.transferPrepare(xfer, buff, size, 0)
flushCache(uintptr(unsafe.Pointer(buff)), uintptr(size))
d.endpointTransmit(descHIDEndpointSerialTx, xfer)
hid.txSerialHead += 1
if hid.txSerialHead >= descHIDSerialTDCount {
hid.txSerialHead = 0
}
hid.txSerialFree = 0
}
// =============================================================================
// [HID] Keyboard
// =============================================================================
func (d *dhw) keyboard() *Keyboard { return descHID[d.cc.config-1].keyboard }
func (d *dhw) keyboardConfigure() {
hid := &descHID[d.cc.config-1]
// Initialize keyboard
hid.keyboard.configure(d.dcd, hid)
switch d.speed() {
case descDeviceSpeedHigh:
hid.txKeyboardSize = descHIDKeyboardTxHSPacketSize
default:
hid.txKeyboardSize = descHIDKeyboardTxFSPacketSize
}
d.endpointEnable(descHIDEndpointKeyboard,
false, descHIDConfigAttrKeyboard)
d.endpointEnable(descHIDEndpointMediaKey,
false, descHIDConfigAttrMediaKey)
d.endpointConfigureTx(descHIDEndpointKeyboard,
hid.txKeyboardSize, false, nil)
d.endpointConfigureTx(descHIDEndpointMediaKey,
hid.txKeyboardSize, false, nil)
}
func (d *dhw) keyboardSendKeys(consumer bool) bool {
hid := &descHID[d.cc.config-1]
if !consumer {
hid.tpKeyboard[0] = hid.keyboard.mod
hid.tpKeyboard[1] = 0
hid.tpKeyboard[2] = hid.keyboard.key[0]
hid.tpKeyboard[3] = hid.keyboard.key[1]
hid.tpKeyboard[4] = hid.keyboard.key[2]
hid.tpKeyboard[5] = hid.keyboard.key[3]
hid.tpKeyboard[6] = hid.keyboard.key[4]
hid.tpKeyboard[7] = hid.keyboard.key[5]
return d.keyboardWrite(descHIDEndpointKeyboard, hid.tpKeyboard[:])
} else {
// 44444444 44333333 33332222 22222211 11111111 [ word ]
// 98765432 10987654 32109876 54321098 76543210 [ index ] (right-to-left)
hid.tpKeyboard[1] = uint8((hid.keyboard.con[1] << 2) | ((hid.keyboard.con[0] >> 8) & 0x03))
hid.tpKeyboard[2] = uint8((hid.keyboard.con[2] << 4) | ((hid.keyboard.con[1] >> 6) & 0x0F))
hid.tpKeyboard[3] = uint8((hid.keyboard.con[3] << 6) | ((hid.keyboard.con[2] >> 4) & 0x3F))
hid.tpKeyboard[4] = uint8(hid.keyboard.con[3] >> 2)
hid.tpKeyboard[5] = hid.keyboard.sys[0]
hid.tpKeyboard[6] = hid.keyboard.sys[1]
hid.tpKeyboard[7] = hid.keyboard.sys[2]
return d.keyboardWrite(descHIDEndpointMediaKey, hid.tpKeyboard[:])
}
}
func (d *dhw) keyboardWrite(endpoint uint8, data []uint8) bool {
hid := &descHID[d.cc.config-1]
size := uint16(len(data))
xfer := &hid.tdKeyboard[hid.txKeyboardHead]
when := ticks()
for {
if 0 == xfer.token&0x80 {
if 0 != xfer.token&0x68 {
// TODO: token contains error, how to handle?
}
hid.txKeyboardPrev = false
break
}
if hid.txKeyboardPrev {
return false
}
if ticks()-when > descHIDKeyboardTxTimeoutMs {
// Waited too long, assume host connection dropped
hid.txKeyboardPrev = true
return false
}
}
// Without this delay, the order packets are transmitted is seriously screwy.
udelay(60)
buff := hid.txKeyboard[hid.txKeyboardHead*descHIDKeyboardTxSize:]
_ = copy(buff, data)
d.transferPrepare(xfer, &buff[0], size, 0)
flushCache(uintptr(unsafe.Pointer(&buff[0])), descHIDKeyboardTxSize)
d.endpointTransmit(endpoint, xfer)
hid.txKeyboardHead += 1
if hid.txKeyboardHead >= descHIDKeyboardTDCount {
hid.txKeyboardHead = 0
}
return true
}
// =============================================================================
// [HID] Mouse
// =============================================================================
func (d *dhw) mouseConfigure() {
hid := &descHID[d.cc.config-1]
switch d.speed() {
case descDeviceSpeedHigh:
hid.txMouseSize = descHIDMouseTxHSPacketSize
default:
hid.txMouseSize = descHIDMouseTxFSPacketSize
}
d.endpointEnable(descHIDEndpointMouse,
false, descHIDConfigAttrMouse)
d.endpointConfigureTx(descHIDEndpointMouse,
hid.txMouseSize, false, nil)
}
// =============================================================================
// [HID] Joystick
// =============================================================================
func (d *dhw) joystickConfigure() {
hid := &descHID[d.cc.config-1]
switch d.speed() {
case descDeviceSpeedHigh:
hid.txJoystickSize = descHIDJoystickTxHSPacketSize
default:
hid.txJoystickSize = descHIDJoystickTxFSPacketSize
}
d.endpointEnable(descHIDEndpointJoystick,
false, descHIDConfigAttrJoystick)
d.endpointConfigureTx(descHIDEndpointJoystick,
hid.txJoystickSize, false, nil)
}
+42
View File
@@ -0,0 +1,42 @@
package usb
import (
"errors"
)
var (
ErrHIDInvalidPort = errors.New("invalid USB port")
ErrHIDInvalidCore = errors.New("invalid USB core")
ErrHIDReportTransfer = errors.New("failed to transfer HID report")
)
type HID struct {
Port int
core *core
}
type HIDConfig struct {
// Port is the MCU's native USB core number. If in doubt, leave it
// uninitialized for default (0).
Port int
}
func (hid *HID) Configure(config HIDConfig) error {
if config.Port >= CoreCount || config.Port >= dcdCount {
return ErrHIDInvalidPort
}
hid.Port = config.Port
// verify we have a free USB port and take ownership of it
var st status
hid.core, st = initCore(hid.Port, class{id: classDeviceHID, config: 1})
if !st.ok() {
return ErrHIDInvalidPort
}
return nil
}
func (hid *HID) Keyboard() *Keyboard {
return hid.core.dc.keyboard()
}
File diff suppressed because it is too large Load Diff
+14 -13
View File
@@ -11,28 +11,29 @@ var (
ErrUARTWriteFailed = errors.New("USB write failure")
)
type (
UARTConfig struct {
BaudRate uint32
}
// UART represents a virtual serial (UART) device emulation using the USB
// CDC-ACM device class driver.
type UART struct {
Port int
core *core
}
// 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
}
)
type UARTConfig struct {
// Port is the MCU's native USB core number. If in doubt, leave it
// uninitialized for default (0).
Port int
}
func (uart *UART) Configure(config UARTConfig) error {
if uart.port >= CoreCount || uart.port >= dcdCount {
if config.Port >= CoreCount || config.Port >= dcdCount {
return ErrUARTInvalidPort
}
uart.Port = config.Port
// verify we have a free USB port and take ownership of it
var st status
uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1})
uart.core, st = initCore(uart.Port, class{id: classDeviceCDCACM, config: 1})
if !st.ok() {
return ErrUARTInvalidPort
}
+3 -2
View File
@@ -106,14 +106,15 @@ type class struct {
// Enumerated constants for all host/device class configurations.
const (
classDeviceCDCACM = 0 // The only currently-supported class (CDC-ACM)
classDeviceCDCACM = 0
classDeviceHID = 1
)
// mode returns the USB core operating mode of the receiver class c.
//go:inline
func (c class) mode() int {
switch c.id {
case classDeviceCDCACM:
case classDeviceCDCACM, classDeviceHID:
return modeDevice
default:
return modeIdle
+55
View File
@@ -1,5 +1,8 @@
package usb
//go:linkname ticks runtime.ticks
func ticks() int64
// leU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have little-endian ordering; that is, the first element
@@ -214,3 +217,55 @@ func endpointIndex(address uint8) uint8 {
return ((address & descEndptAddrNumberMsk) << 1) |
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
}
// The following buffLo and buffHi are helper methods for slice definitions from
// potentially zero-length arrays (depending on compile-time constants).
//
// For example, if we have an array containing a 5-element buffer for three
// instances of some device class (15 total elements), partitioned as follows,
// then we compute the indices for instance 2 as usual:
//
// Index: 01234 56789 ABCDE
// Array: [ 1 | 2 | 3 ]
//
// Lo: (n-1) * size => (2-1) * 5 => 5
// Hi: (n) * size => (2) * 5 => 10 (0xA)
//
// However, if we have specified (via const definition) that 0 instances of some
// device class be allocated, then the associated device class buffer arrays
// will all be zero-length arrays, and the arithmetic to compute the slice
// indices used above will result in out-of-bounds indices:
//
// Index:
// Array: []
//
// Lo: (n-1) * size => (2-1) * 5 => 5 [Error!]
// Hi: (n) * size => (2) * 5 => 10 (0xA) [Error!]
//
//
// I couldn't figure out a straight-forward way to resolve these slice indices
// using only arithmetic, so I've resorted to simple conditionals. If the number
// of instances for some given class is zero (count=0), defined via compile-time
// constant, then just use the empty slice range [0:0].
// buffLo returns the starting array slice index for the n'th region of size
// elements from an array containing count regions of size elements.
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
// argument equals 0.
func buffLo(n, count, size uint16) uint16 {
if 0 == n || 0 == count || 0 == size {
return 0
}
return (n - 1) * size
}
// buffHi returns the ending array slice index for the n'th region of size
// elements from an array containing count regions of size elements.
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
// argument equals 0.
func buffHi(n, count, size uint16) uint16 {
if 0 == n || 0 == count || 0 == size {
return 0
}
return n * size
}
-3
View File
@@ -4,9 +4,6 @@ package usb
import "device/arm"
//go:linkname ticks runtime.ticks
func ticks() int64
// 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.
+3 -1
View File
@@ -7,6 +7,7 @@ import (
"device/arm"
"device/nxp"
"machine"
"machine/usb"
"math/bits"
"unsafe"
)
@@ -124,7 +125,8 @@ func initUART() {
}
func initUSB() {
machine.UART0.Configure(machine.UARTConfig{})
machine.HID0.Configure(usb.HIDConfig{})
// machine.UART0.Configure(usb.UARTConfig{})
}
func putchar(c byte) {