mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-13 15:33:40 +00:00
implemented USB HID composite keyboard support
This commit is contained in:
@@ -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"))
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"device/nxp"
|
"device/nxp"
|
||||||
|
"machine/usb"
|
||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,11 +110,9 @@ func init() {
|
|||||||
// | USB |
|
// | USB |
|
||||||
// #=====================================================#
|
// #=====================================================#
|
||||||
var (
|
var (
|
||||||
// USBCDC is a legacy class being retained here as temporary wrapper.
|
// UART0 = usb.UART{Port: 0}
|
||||||
// See godoc comments on type USBCDC struct definition for details.
|
HID0 = usb.HID{Port: 0}
|
||||||
UART0 = USBCDC{
|
UART0 = &UART1
|
||||||
port: 0, // USB_OTG1 (Micro-B port on Teensy 4.0/4.1)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// #=====================================================#
|
// #=====================================================#
|
||||||
|
|||||||
@@ -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
@@ -12,7 +12,7 @@ func init() {
|
|||||||
|
|
||||||
// dcdCount defines the number of USB cores to configure for device mode. It is
|
// dcdCount defines the number of USB cores to configure for device mode. It is
|
||||||
// computed as the sum of all declared device configuration descriptors.
|
// 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
|
// dcdInstance provides statically-allocated instances of each USB device
|
||||||
// controller configured on this platform.
|
// controller configured on this platform.
|
||||||
@@ -134,7 +134,6 @@ func (d *dcd) event(ev dcdEvent) {
|
|||||||
case dcdStageSetup:
|
case dcdStageSetup:
|
||||||
case dcdStageData:
|
case dcdStageData:
|
||||||
case dcdStageStatus:
|
case dcdStageStatus:
|
||||||
d.controlStatus()
|
|
||||||
case dcdStageStall:
|
case dcdStageStall:
|
||||||
d.controlStall()
|
d.controlStall()
|
||||||
}
|
}
|
||||||
@@ -180,7 +179,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
|
|
||||||
// SET ADDRESS (0x05):
|
// SET ADDRESS (0x05):
|
||||||
case descRequestStandardSetAddress:
|
case descRequestStandardSetAddress:
|
||||||
d.controlDeviceAddress(sup.wValue)
|
d.setDeviceAddress(sup.wValue)
|
||||||
d.controlReceive(uintptr(0), 0, false)
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
return dcdStageSetup
|
return dcdStageSetup
|
||||||
|
|
||||||
@@ -200,6 +199,14 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
d.uartConfigure()
|
d.uartConfigure()
|
||||||
d.controlReceive(uintptr(0), 0, false)
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
|
|
||||||
|
// HID
|
||||||
|
case classDeviceHID:
|
||||||
|
d.serialConfigure()
|
||||||
|
d.keyboardConfigure()
|
||||||
|
d.mouseConfigure()
|
||||||
|
d.joystickConfigure()
|
||||||
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device class
|
// Unhandled device class
|
||||||
}
|
}
|
||||||
@@ -225,8 +232,23 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
|
|
||||||
// GET DESCRIPTOR (0x06):
|
// GET DESCRIPTOR (0x06):
|
||||||
case descRequestStandardGetDescriptor:
|
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):
|
// GET CONFIGURATION (0x08):
|
||||||
case descRequestStandardGetConfiguration:
|
case descRequestStandardGetConfiguration:
|
||||||
@@ -247,8 +269,38 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
|
|
||||||
// GET DESCRIPTOR (0x06):
|
// GET DESCRIPTOR (0x06):
|
||||||
case descRequestStandardGetDescriptor:
|
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:
|
default:
|
||||||
// Unhandled request
|
// Unhandled request
|
||||||
@@ -262,11 +314,15 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
|
|
||||||
// CLEAR FEATURE (0x01):
|
// CLEAR FEATURE (0x01):
|
||||||
case descRequestStandardClearFeature:
|
case descRequestStandardClearFeature:
|
||||||
// TODO
|
d.endpointClearFeature(uint8(sup.wIndex))
|
||||||
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
|
return dcdStageSetup
|
||||||
|
|
||||||
// SET FEATURE (0x03):
|
// SET FEATURE (0x03):
|
||||||
case descRequestStandardSetFeature:
|
case descRequestStandardSetFeature:
|
||||||
// TODO
|
d.endpointSetFeature(uint8(sup.wIndex))
|
||||||
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
|
return dcdStageSetup
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled request
|
// Unhandled request
|
||||||
@@ -322,6 +378,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
d.controlReceive(
|
d.controlReceive(
|
||||||
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
||||||
descCDCACMCodingSize, true)
|
descCDCACMCodingSize, true)
|
||||||
|
// CDC Line Coding packet receipt handling occurs in method
|
||||||
|
// controlComplete().
|
||||||
return dcdStageSetup
|
return dcdStageSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,11 +396,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
// CDC-ACM (single)
|
// CDC-ACM (single)
|
||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM:
|
||||||
|
|
||||||
// Determine interface destination of the notification
|
// Determine interface destination of the request
|
||||||
switch sup.wIndex {
|
switch sup.wIndex {
|
||||||
|
|
||||||
// Control/status interface:
|
// Control/status interface:
|
||||||
case descCDCACMInterfaceCtrl:
|
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)
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
return dcdStageSetup
|
return dcdStageSetup
|
||||||
|
|
||||||
@@ -369,6 +429,79 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
// Unhandled device class
|
// 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:
|
default:
|
||||||
// Unhandled request
|
// Unhandled request
|
||||||
}
|
}
|
||||||
@@ -419,15 +552,14 @@ func (d *dcd) controlComplete(status uint32) {
|
|||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM:
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
|
|
||||||
// Determine interface destination of the notification
|
// Determine interface destination of the request
|
||||||
switch d.setup.wIndex {
|
switch d.setup.wIndex {
|
||||||
|
|
||||||
// Control/status interface:
|
// CDC-ACM Control Interface:
|
||||||
case descCDCACMInterfaceCtrl:
|
case descCDCACMInterfaceCtrl:
|
||||||
|
|
||||||
// Notify PHY to handle triggers like special baud rates, which
|
// Notify PHY to handle triggers like special baud rates, which
|
||||||
// signal to reboot into bootloader or begin receiving OTA updates
|
// signal to reboot into bootloader or begin receiving OTA updates
|
||||||
d.controlLineCoding(descCDCACMLineCoding{
|
d.uartSetLineCoding(descCDCACMLineCoding{
|
||||||
baud: packU32(acm.cx[:]),
|
baud: packU32(acm.cx[:]),
|
||||||
stopBits: acm.cx[4],
|
stopBits: acm.cx[4],
|
||||||
parity: acm.cx[5],
|
parity: acm.cx[5],
|
||||||
@@ -442,6 +574,60 @@ func (d *dcd) controlComplete(status uint32) {
|
|||||||
// Unhandled device class
|
// 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:
|
default:
|
||||||
// Unhandled request
|
// 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
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
switch d.cc.id {
|
dxn := uint8(0)
|
||||||
|
|
||||||
// CDC-ACM (single)
|
// Determine the type of descriptor being requested
|
||||||
case classDeviceCDCACM:
|
switch sup.wValue >> 8 {
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
|
||||||
dxn := uint8(0)
|
|
||||||
|
|
||||||
// Determine the type of descriptor being requested
|
// Device descriptor
|
||||||
switch sup.wValue >> 8 {
|
case descTypeDevice:
|
||||||
|
dxn = descLengthDevice
|
||||||
|
_ = copy(acm.dx[:], acm.device[:dxn])
|
||||||
|
|
||||||
// Device descriptor
|
// Configuration descriptor
|
||||||
case descTypeDevice:
|
case descTypeConfigure:
|
||||||
dxn = descLengthDevice
|
dxn = uint8(descCDCACMConfigSize)
|
||||||
_ = copy(acm.dx[:], acm.device[:dxn])
|
_ = copy(acm.dx[:], acm.config[:dxn])
|
||||||
|
|
||||||
// Configuration descriptor
|
// String descriptor
|
||||||
case descTypeConfigure:
|
case descTypeString:
|
||||||
dxn = uint8(descCDCACMConfigSize)
|
if 0 == len(acm.locale) {
|
||||||
_ = copy(acm.dx[:], acm.config[:dxn])
|
break // No string descriptors defined!
|
||||||
|
}
|
||||||
|
var sd []uint8
|
||||||
|
if 0 == uint8(sup.wValue) {
|
||||||
|
|
||||||
// String descriptor
|
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||||
case descTypeString:
|
// strings in some given language. This case (setup.wValue = [0x03]00)
|
||||||
if 0 == len(acm.locale) {
|
// is a string request from the host to determine what that language is.
|
||||||
break // No string descriptors defined!
|
//
|
||||||
|
// 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
|
sd = acm.locale[code].descriptor[sup.wValue&0xFF][:]
|
||||||
if 0 == uint8(sup.wValue) {
|
|
||||||
|
|
||||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
} else {
|
||||||
// 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 {
|
// 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
|
// Found language with a string defined at the requested index.
|
||||||
// previous request (above: setup.wValue = [0x03]00). We need to locate
|
//
|
||||||
// the set of strings whose language matches the language code given in
|
// TODO: Add API methods to device controller that allows the user
|
||||||
// this new setup.wIndex.
|
// to provide these strings at/before driver initialization.
|
||||||
for code := range acm.locale {
|
//
|
||||||
if sup.wIndex == acm.locale[code].language {
|
// For now, we just always use the descCommon* strings.
|
||||||
// Found language, check if string descriptor at given index exists
|
var s string
|
||||||
if int(sup.wValue&0xFF) < len(acm.locale[code].descriptor) {
|
switch uint8(sup.wValue) {
|
||||||
|
case 1:
|
||||||
// Found language with a string defined at the requested index.
|
s = descCommonManufacturer
|
||||||
//
|
case 2:
|
||||||
// TODO: Add API methods to device controller that allows the user
|
s = descCommonProduct + " CDC-ACM"
|
||||||
// to provide these strings at/before driver initialization.
|
case 3:
|
||||||
//
|
s = descCommonSerialNumber
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
// Copy string descriptor into descriptor transmit buffer
|
||||||
dxn = sd[0]
|
if nil != sd && len(sd) >= 0 {
|
||||||
_ = copy(acm.dx[:], sd[:dxn])
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dxn > 0 {
|
// Device qualification descriptor
|
||||||
if dxn > uint8(sup.wLength) {
|
case descTypeQualification:
|
||||||
dxn = uint8(sup.wLength)
|
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(
|
sd = hid.locale[code].descriptor[sup.wValue&0xFF][:]
|
||||||
uintptr(unsafe.Pointer(&acm.dx[0])), uintptr(dxn))
|
|
||||||
d.controlTransmit(
|
} else {
|
||||||
uintptr(unsafe.Pointer(&acm.dx[0])), uint32(dxn), false)
|
|
||||||
|
// 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:
|
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
@@ -304,152 +304,75 @@ const (
|
|||||||
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
|
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
|
||||||
)
|
)
|
||||||
|
|
||||||
// descCDCACM0Device holds the default device descriptor for CDC-ACM[0], i.e.,
|
// USB HID constants defined per specification
|
||||||
// configuration index 1.
|
const (
|
||||||
var descCDCACM0Device = [descLengthDevice]uint8{
|
// HID class
|
||||||
descLengthDevice, // Size of this descriptor in bytes
|
descHIDType = 0x03
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// descCDCACM0Qualif holds the default device qualification descriptor for
|
// HID subclass
|
||||||
// CDC-ACM[0], i.e., configuration index 1.
|
descHIDSubNone = 0x00
|
||||||
var descCDCACM0Qualif = [descLengthQualification]uint8{
|
descHIDSubBoot = 0x01
|
||||||
descLengthQualification, // Size of this descriptor in bytes
|
|
||||||
descTypeQualification, // Descriptor Type
|
// HID protocol
|
||||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
descHIDProtoNone = 0x00
|
||||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
descHIDProtoKeyboard = 0x01
|
||||||
descCDCTypeComm, // Class code (assigned by the USB-IF).
|
descHIDProtoMouse = 0x02
|
||||||
descCDCSubNone, // Subclass code (assigned by the USB-IF).
|
|
||||||
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
|
descHIDRequestGetReport = 0x01 // HID request GET_REPORT
|
||||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
descHIDRequestGetReportTypeInput = 0x01 // HID request GET_REPORT type INPUT
|
||||||
descCDCACMCount, // Number of possible configurations
|
descHIDRequestGetReportTypeOutput = 0x02 // HID request GET_REPORT type OUTPUT
|
||||||
0, // Reserved
|
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 (
|
const (
|
||||||
// Size of all CDC-ACM configuration descriptors.
|
// Size of all CDC-ACM configuration descriptors.
|
||||||
descCDCACMConfigSize = uint16(
|
descCDCACMConfigSize = uint16(
|
||||||
descLengthConfigure + // configuration
|
descLengthConfigure + // Configuration Header
|
||||||
descLengthInterface + // communication/control interface
|
descLengthInterface + // CDC Interface Descriptor
|
||||||
descCDCFuncLengthHeader + // CDC header
|
descCDCFuncLengthHeader + // CDC Header
|
||||||
descCDCFuncLengthCallManagement + // CDC call management
|
descCDCFuncLengthCallManagement + // CDC Call Management Func Descriptor
|
||||||
descCDCFuncLengthAbstractControl + // CDC abstract control
|
descCDCFuncLengthAbstractControl + // CDC Abstract Control Func Descriptor
|
||||||
descCDCFuncLengthUnion + // CDC union
|
descCDCFuncLengthUnion + // CDC Union Functional Descriptor
|
||||||
descLengthEndpoint + // communication/control input endpoint
|
descLengthEndpoint + // CDC Status IN Endpoint Descriptor
|
||||||
descLengthInterface + // data interface
|
descLengthInterface + // CDC Data Interface Descriptor
|
||||||
descLengthEndpoint + // data input endpoint
|
descLengthEndpoint + // CDC Data IN Endpoint Descriptor
|
||||||
descLengthEndpoint) // data output endpoint
|
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 (
|
type (
|
||||||
// descString is the actual byte array used to hold string descriptors. The
|
// 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
|
// 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.
|
// 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.
|
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
|
||||||
const descCDCACMCodingSize = 7
|
const descCDCACMCodingSize = 7
|
||||||
|
|
||||||
@@ -514,23 +415,19 @@ type descCDCACMLineCoding struct {
|
|||||||
|
|
||||||
// Common configuration constants for the USB CDC-ACM (single) device class.
|
// Common configuration constants for the USB CDC-ACM (single) device class.
|
||||||
const (
|
const (
|
||||||
// String descriptor languages available
|
descCDCACMLanguageCount = 1 // String descriptor languages available
|
||||||
descCDCACMLanguageCount = 1
|
|
||||||
|
|
||||||
// Interfaces for all CDC-ACM configurations.
|
descCDCACMInterfaceCount = 2 // Interfaces for all CDC-ACM configurations.
|
||||||
descCDCACMInterfaceCount = 2
|
descCDCACMEndpointCount = 4 // Endpoints for all CDC-ACM configurations.
|
||||||
descCDCACMInterfaceCtrl = 0
|
|
||||||
descCDCACMInterfaceData = 1
|
|
||||||
|
|
||||||
// Endpoints for all CDC-ACM configurations.
|
descCDCACMInterfaceCtrl = 0 // CDC-ACM Control Interface
|
||||||
descCDCACMEndpointCount = 4
|
descCDCACMEndpointStatus = 2 // CDC-ACM Interrupt IN Endpoint
|
||||||
descCDCACMEndpointStatus = 2 // Communication/control interrupt input
|
|
||||||
descCDCACMEndpointDataRx = 3 // Bulk data output
|
|
||||||
descCDCACMEndpointDataTx = 4 // Bulk data input
|
|
||||||
|
|
||||||
// Endpoint configuration attributes for all CDC-ACM configurations.
|
|
||||||
descCDCACMConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
|
descCDCACMConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
|
||||||
|
|
||||||
|
descCDCACMInterfaceData = 1 // CDC-ACM Data Interface
|
||||||
|
descCDCACMEndpointDataRx = 3 // CDC-ACM Bulk Data OUT (Rx) Endpoint
|
||||||
descCDCACMConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
|
descCDCACMConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
|
||||||
|
descCDCACMEndpointDataTx = 4 // CDC-ACM Bulk Data IN (Tx) Endpoint
|
||||||
descCDCACMConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
|
descCDCACMConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -547,14 +444,600 @@ type descCDCACMClass struct {
|
|||||||
|
|
||||||
// descCDCACM holds statically-allocated instances for each of the CDC-ACM
|
// descCDCACM holds statically-allocated instances for each of the CDC-ACM
|
||||||
// (single) device class configurations, ordered by index (offset by -1).
|
// (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
|
{ // CDC-ACM (single) class configuration index 1
|
||||||
descCDCACMClassData: &descCDCACMData[0],
|
descCDCACMClassData: &descCDCACMData[0],
|
||||||
|
|
||||||
locale: &descCDCACM0String,
|
locale: &[descCDCACMLanguageCount]descStringLanguage{
|
||||||
device: &descCDCACM0Device,
|
|
||||||
qualif: &descCDCACM0Qualif,
|
{ // [0x0409] US English
|
||||||
config: &descCDCACM0Config,
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,14 @@ package usb
|
|||||||
// descCPUFrequencyHz defines the target CPU frequency (Hz).
|
// descCPUFrequencyHz defines the target CPU frequency (Hz).
|
||||||
const descCPUFrequencyHz = 600000000
|
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.
|
// General USB device identification constants.
|
||||||
const (
|
const (
|
||||||
descCommonVendorID = 0x16C0
|
descCommonVendorID = 0x16C0
|
||||||
@@ -12,39 +20,166 @@ const (
|
|||||||
descCommonReleaseID = 0x0101 // BCD (1.1)
|
descCommonReleaseID = 0x0101 // BCD (1.1)
|
||||||
|
|
||||||
descCommonLanguage = descLanguageEnglish
|
descCommonLanguage = descLanguageEnglish
|
||||||
descCommonManufacturer = "NXP Semiconductors"
|
descCommonManufacturer = "TinyGo"
|
||||||
descCommonProduct = "TinyGo USB"
|
descCommonProduct = "USB"
|
||||||
descCommonSerialNumber = "1"
|
descCommonSerialNumber = "00000"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants for USB CDC-ACM device classes.
|
// Constants for USB CDC-ACM device classes.
|
||||||
const (
|
const (
|
||||||
// descCDCACMCount defines the number of USB cores that will be configured as
|
descCDCACMMaxPower = 50 // 100 mA
|
||||||
// CDC-ACM (single) devices.
|
|
||||||
descCDCACMCount = 1
|
// CDC-ACM Control Buffers
|
||||||
|
|
||||||
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
|
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
|
||||||
descCDCACMRDCount = 2 * descCDCACMEndpointCount
|
|
||||||
descCDCACMTDCount = descCDCACMEndpointCount
|
|
||||||
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
|
|
||||||
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
|
|
||||||
descCDCACMCxCount = 8
|
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
|
descCDCACMTxTimeoutMs = 120 // millisec
|
||||||
descCDCACMTxSyncUs = 75 // microsec
|
descCDCACMTxSyncUs = 75 // microsec
|
||||||
|
|
||||||
descCDCACMStatusPacketSize = 16
|
// Default CDC-ACM Endpoint Configurations (High-Speed)
|
||||||
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // high-speed
|
|
||||||
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // high-speed
|
|
||||||
descCDCACMRxSize = descCDCACMDataRxPacketSize
|
|
||||||
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
|
|
||||||
|
|
||||||
descCDCACMDataRxFSPacketSize = 64 // full-speed
|
descCDCACMStatusInterval = descCDCACMStatusHSInterval // Status
|
||||||
descCDCACMDataTxFSPacketSize = 64 // full-speed
|
descCDCACMStatusPacketSize = descCDCACMStatusHSPacketSize //
|
||||||
descCDCACMDataRxHSPacketSize = 512 // high-speed
|
|
||||||
descCDCACMDataTxHSPacketSize = 512 // high-speed
|
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
|
// descCDCACM0QH is an array of endpoint queue heads, which is where all
|
||||||
@@ -71,18 +206,28 @@ const (
|
|||||||
//go:align 4096
|
//go:align 4096
|
||||||
var descCDCACM0QH [descCDCACMQHCount]dhwEndpoint
|
var descCDCACM0QH [descCDCACMQHCount]dhwEndpoint
|
||||||
|
|
||||||
// descCDCACM0CD is the transfer descriptor for data messages transmitted or
|
// descCDCACM0CD is the transfer descriptor for messages transmitted or received
|
||||||
// received on the status/control endpoint 0 for the default CDC-ACM (single)
|
// on the status/control endpoint 0 for the default CDC-ACM (single) device
|
||||||
// device class configuration (index 1).
|
// class configuration (index 1).
|
||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0CD dhwTransfer
|
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
|
// descCDCACM0AD is the transfer descriptor for ackowledgement (ACK) messages
|
||||||
// transmitted or received on the status/control endpoint 0 for the default
|
// transmitted or received on the status/control endpoint 0 for the default
|
||||||
// CDC-ACM (single) device class configuration (index 1).
|
// CDC-ACM (single) device class configuration (index 1).
|
||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0AD dhwTransfer
|
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,
|
// descCDCACM0RD is an array of transfer descriptors for Rx (OUT) transfers,
|
||||||
// which describe to the device controller the location and quantity of data
|
// 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
|
// being received for a given transfer, for the default CDC-ACM (single) device
|
||||||
@@ -90,6 +235,11 @@ var descCDCACM0AD dhwTransfer
|
|||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
|
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,
|
// descCDCACM0TD is an array of transfer descriptors for Tx (IN) transfers,
|
||||||
// which describe to the device controller the location and quantity of data
|
// which describe to the device controller the location and quantity of data
|
||||||
// being transmitted for a given transfer, for the default CDC-ACM (single)
|
// being transmitted for a given transfer, for the default CDC-ACM (single)
|
||||||
@@ -97,36 +247,16 @@ var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
|
|||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0TD [descCDCACMTDCount]dhwTransfer
|
var descCDCACM0TD [descCDCACMTDCount]dhwTransfer
|
||||||
|
|
||||||
// descCDCACM0LineCoding holds the emulated UART line coding for the default
|
// descCDCACM0Tx is the transmit (Tx) transfer buffer for the default CDC-ACM
|
||||||
// CDC-ACM (single) device class configuration (index 1).
|
// (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).
|
|
||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0Tx [descCDCACMTxCount]uint8
|
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 descCDCACM0RDNum [descCDCACMRDCount]uint16
|
||||||
var descCDCACM0RDIdx [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
|
// (single) device class configurations, ordered by index (offset by -1), for
|
||||||
// iMXRT1062 targets only.
|
// iMXRT1062 targets only.
|
||||||
//
|
//
|
||||||
@@ -134,21 +264,30 @@ var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
|
|||||||
// of the common/target-agnostic CDC-ACM class configurations (descCDCACM).
|
// of the common/target-agnostic CDC-ACM class configurations (descCDCACM).
|
||||||
// Methods defined on this type implement target-specific functionality, and
|
// Methods defined on this type implement target-specific functionality, and
|
||||||
// some of these methods are required by the common device controller driver.
|
// 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 {
|
type descCDCACMClassData struct {
|
||||||
|
|
||||||
|
// CDC-ACM Control Buffers
|
||||||
|
|
||||||
qh *[descCDCACMQHCount]dhwEndpoint // endpoint queue heads
|
qh *[descCDCACMQHCount]dhwEndpoint // endpoint queue heads
|
||||||
|
|
||||||
cd *dhwTransfer // control endpoint 0 Rx/Tx data transfer descriptor
|
cd *dhwTransfer // control endpoint 0 Rx/Tx 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
|
|
||||||
|
|
||||||
cx *[descCDCACMCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
cx *[descCDCACMCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
||||||
rx *[descCDCACMRxCount]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
|
||||||
tx *[descCDCACMTxCount]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||||
dx *[descCDCACMConfigSize]uint8 // descriptor data Tx (IN) 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
|
rxSize uint16
|
||||||
txSize uint16
|
txSize uint16
|
||||||
|
|
||||||
@@ -159,40 +298,307 @@ type descCDCACMClassData struct {
|
|||||||
rxHead uint8
|
rxHead uint8
|
||||||
rxTail uint8
|
rxTail uint8
|
||||||
rxFree uint16
|
rxFree uint16
|
||||||
|
|
||||||
rxCount *[descCDCACMRDCount]uint16
|
|
||||||
rxIndex *[descCDCACMRDCount]uint16
|
|
||||||
rxQueue *[descCDCACMRDCount + 1]uint16
|
|
||||||
|
|
||||||
_ [2]uint8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// descCDCACMData holds statically-allocated instances for each of the target-
|
// descCDCACMData holds statically-allocated instances for each of the target-
|
||||||
// specific (iMXRT1062) CDC-ACM (single) device class configurations' control
|
// specific (iMXRT1062) CDC-ACM (single) device class configurations' control
|
||||||
// and data structures, ordered by configuration index (offset by -1). Each
|
// and data structures, ordered by configuration index (offset by -1). Each
|
||||||
// element is embedded in a corresponding element of descCDCACM.
|
// element is embedded in a corresponding element of descCDCACM.
|
||||||
//go:align 32
|
//go:align 64
|
||||||
var descCDCACMData = [descCDCACMCount]descCDCACMClassData{
|
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,
|
qh: &descCDCACM0QH,
|
||||||
|
|
||||||
cd: &descCDCACM0CD,
|
cd: &descCDCACM0CD,
|
||||||
ad: &descCDCACM0AD,
|
|
||||||
rd: &descCDCACM0RD,
|
|
||||||
td: &descCDCACM0TD,
|
|
||||||
|
|
||||||
cx: &descCDCACM0Cx,
|
cx: &descCDCACM0Cx,
|
||||||
rx: &descCDCACM0Rx,
|
ad: &descCDCACM0AD,
|
||||||
tx: &descCDCACM0Tx,
|
|
||||||
dx: &descCDCACM0Dx,
|
dx: &descCDCACM0Dx,
|
||||||
|
|
||||||
cxSize: descCDCACMStatusPacketSize,
|
// CDC-ACM Data Buffers
|
||||||
rxSize: descCDCACMDataRxPacketSize,
|
|
||||||
txSize: descCDCACMDataTxPacketSize,
|
rd: &descCDCACM0RD,
|
||||||
|
rx: &descCDCACM0Rx,
|
||||||
|
td: &descCDCACM0TD,
|
||||||
|
tx: &descCDCACM0Tx,
|
||||||
|
|
||||||
rxCount: &descCDCACM0RDNum,
|
rxCount: &descCDCACM0RDNum,
|
||||||
rxIndex: &descCDCACM0RDIdx,
|
rxIndex: &descCDCACM0RDIdx,
|
||||||
rxQueue: &descCDCACM0RDQue,
|
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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ type dhw struct {
|
|||||||
sofUsage uint8
|
sofUsage uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runBootloader() { arm.Asm(`bkpt #251`) }
|
||||||
|
|
||||||
// cycleCount uses the ARM debug cycle counter available on iMXRT1062 (enabled
|
// 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.
|
// in runtime_mimxrt1062_time.go) to return the number of CPU cycles since boot.
|
||||||
//go:inline
|
//go:inline
|
||||||
@@ -184,7 +186,9 @@ func (d *dhw) enableSOF(enable bool, iface uint8) {
|
|||||||
d.bus.USBINTR.SetBits(nxp.USB_USBINTR_SRE)
|
d.bus.USBINTR.SetBits(nxp.USB_USBINTR_SRE)
|
||||||
}
|
}
|
||||||
arm.EnableInterrupts(ivm)
|
arm.EnableInterrupts(ivm)
|
||||||
|
d.timerReboot = 80
|
||||||
} else {
|
} else {
|
||||||
|
d.timerReboot = 0
|
||||||
d.sofUsage &^= 1 << iface
|
d.sofUsage &^= 1 << iface
|
||||||
if 0 == d.sofUsage {
|
if 0 == d.sofUsage {
|
||||||
d.bus.USBINTR.ClearBits(nxp.USB_USBINTR_SRE)
|
d.bus.USBINTR.ClearBits(nxp.USB_USBINTR_SRE)
|
||||||
@@ -354,33 +358,23 @@ func (d *dhw) interrupt() {
|
|||||||
d.timerReboot -= 1
|
d.timerReboot -= 1
|
||||||
if 0 == d.timerReboot {
|
if 0 == d.timerReboot {
|
||||||
d.enableSOF(false, descCDCACMInterfaceCount)
|
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 |
|
d.bus.DEVICEADDR.Set(nxp.USB_DEVICEADDR_USBADRA |
|
||||||
((uint32(addr) << nxp.USB_DEVICEADDR_USBADR_Pos) &
|
((uint32(addr) << nxp.USB_DEVICEADDR_USBADR_Pos) &
|
||||||
nxp.USB_DEVICEADDR_USBADR_Msk))
|
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)?
|
// Control Endpoint 0
|
||||||
}
|
// =============================================================================
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
|
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
|
||||||
// any other endpoint, use method endpointStall().
|
// any other endpoint, use method endpointStall().
|
||||||
@@ -411,7 +405,7 @@ func (d *dhw) controlReceive(
|
|||||||
} // wait for endpoint finish priming
|
} // wait for endpoint finish priming
|
||||||
}
|
}
|
||||||
ad.next = dhwTransferEOL
|
ad.next = dhwTransferEOL
|
||||||
ad.token = 1 << 7
|
ad.token = 1 << 7 // Bit 7: active transfer
|
||||||
if notify {
|
if notify {
|
||||||
ad.token |= 1 << 15
|
ad.token |= 1 << 15
|
||||||
}
|
}
|
||||||
@@ -424,6 +418,8 @@ func (d *dhw) controlReceive(
|
|||||||
if notify {
|
if notify {
|
||||||
d.controlMask = tm
|
d.controlMask = tm
|
||||||
}
|
}
|
||||||
|
for 0 != d.bus.ENDPTPRIME.Get() {
|
||||||
|
} // wait for endpoint finish priming
|
||||||
}
|
}
|
||||||
|
|
||||||
// controlTransmit transmits (Tx, IN) data on control endpoint 0.
|
// controlTransmit transmits (Tx, IN) data on control endpoint 0.
|
||||||
@@ -449,7 +445,7 @@ func (d *dhw) controlTransmit(
|
|||||||
} // wait for endpoint finish priming
|
} // wait for endpoint finish priming
|
||||||
}
|
}
|
||||||
ad.next = dhwTransferEOL
|
ad.next = dhwTransferEOL
|
||||||
ad.token = 1 << 7
|
ad.token = 1 << 7 // Bit 7: active transfer
|
||||||
if notify {
|
if notify {
|
||||||
ad.token |= 1 << 15
|
ad.token |= 1 << 15
|
||||||
}
|
}
|
||||||
@@ -462,11 +458,13 @@ func (d *dhw) controlTransmit(
|
|||||||
if notify {
|
if notify {
|
||||||
d.controlMask = rm
|
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.
|
// Endpoint Descriptor
|
||||||
const dhwEndpointSize = 64 // bytes
|
// =============================================================================
|
||||||
|
|
||||||
// dhwEndpoint defines a USB standard endpoint, used as the general channel of
|
// dhwEndpoint defines a USB standard endpoint, used as the general channel of
|
||||||
// communication between host and device.
|
// communication between host and device.
|
||||||
@@ -488,6 +486,10 @@ type dhwEndpoint struct {
|
|||||||
callback func(transfer *dhwTransfer)
|
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,
|
// endpointQueueHead returns the queue head for the given endpoint address,
|
||||||
// encoded as direction D and endpoint number N with the 8-bit mask DxxxNNNN.
|
// encoded as direction D and endpoint number N with the 8-bit mask DxxxNNNN.
|
||||||
//go:inline
|
//go:inline
|
||||||
@@ -496,6 +498,8 @@ func (d *dhw) endpointQueueHead(endpoint uint8) *dhwEndpoint {
|
|||||||
switch d.cc.id {
|
switch d.cc.id {
|
||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM:
|
||||||
return &descCDCACM[d.cc.config-1].qh[endpointIndex(endpoint)]
|
return &descCDCACM[d.cc.config-1].qh[endpointIndex(endpoint)]
|
||||||
|
case classDeviceHID:
|
||||||
|
return &descHID[d.cc.config-1].qh[endpointIndex(endpoint)]
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -552,17 +556,23 @@ func (d *dhw) endpointStall(endpoint uint8) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (d *dhw) endpointPrime(mask uint32, transfer *dhwTransfer) {
|
func (d *dhw) endpointClearFeature(endpoint uint8) {
|
||||||
// d.bus.ENDPTPRIME.Set(mask)
|
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 {
|
func (d *dhw) endpointSetFeature(endpoint uint8) {
|
||||||
// return d.bus.ENDPTPRIME.Get()
|
switch endpoint {
|
||||||
// }
|
case rxEndpoint(endpoint):
|
||||||
|
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_RXS)
|
||||||
// func (d *dhw) endpointUnprime(mask uint32) {
|
case txEndpoint(endpoint):
|
||||||
// d.bus.ENDPTCOMPLETE.Set(mask)
|
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_TXS)
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// endpointConfigure configures the given bulk data endpoint for transfer.
|
// endpointConfigure configures the given bulk data endpoint for transfer.
|
||||||
func (d *dhw) endpointConfigure(
|
func (d *dhw) endpointConfigure(
|
||||||
@@ -603,8 +613,8 @@ func (d *dhw) endpointComplete(endpoint uint8) {
|
|||||||
ep.first = nil
|
ep.first = nil
|
||||||
ep.last = nil
|
ep.last = nil
|
||||||
} else {
|
} else {
|
||||||
if 0 != t.token&(1<<7) {
|
if 0 != t.token&(1<<7) { // Bit 7: active transfer
|
||||||
// active transfer, new list begins here
|
// new list begins here
|
||||||
ep.first = t
|
ep.first = t
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
@@ -634,15 +644,23 @@ func (d *dhw) endpointConfigureRx(
|
|||||||
endpoint > descCDCACMEndpointCount {
|
endpoint > descCDCACMEndpointCount {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
|
||||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
// HID
|
||||||
if nil != callback {
|
case classDeviceHID:
|
||||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
if endpoint < descHIDEndpointSerialRx ||
|
||||||
|
endpoint > descHIDEndpointCount {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device class
|
// 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
|
// endpointConfigureTx configures the given bulk data transmit (Tx, IN) endpoint
|
||||||
@@ -659,15 +677,23 @@ func (d *dhw) endpointConfigureTx(
|
|||||||
endpoint > descCDCACMEndpointCount {
|
endpoint > descCDCACMEndpointCount {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
|
||||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
// HID
|
||||||
if nil != callback {
|
case classDeviceHID:
|
||||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
if endpoint < descHIDEndpointSerialRx ||
|
||||||
|
endpoint > descHIDEndpointCount {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device class
|
// 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.
|
// 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 {
|
endpoint > descCDCACMEndpointCount {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
|
||||||
em := (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
// HID
|
||||||
d.transferSchedule(ep, em, transfer)
|
case classDeviceHID:
|
||||||
|
if endpoint < descHIDEndpointSerialRx ||
|
||||||
|
endpoint > descHIDEndpointCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device class
|
// 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
|
// endpointTransmit schedules a transmit (Tx, IN) transfer on the given
|
||||||
@@ -704,17 +738,26 @@ func (d *dhw) endpointTransmit(endpoint uint8, transfer *dhwTransfer) {
|
|||||||
endpoint > descCDCACMEndpointCount {
|
endpoint > descCDCACMEndpointCount {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
|
||||||
em := (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
// HID
|
||||||
d.transferSchedule(ep, em, transfer)
|
case classDeviceHID:
|
||||||
|
if endpoint < descHIDEndpointSerialRx ||
|
||||||
|
endpoint > descHIDEndpointCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device class
|
// 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
|
// dhwTransfer describes the size and location of data to be transferred to or
|
||||||
// from a USB endpoint.
|
// from a USB endpoint.
|
||||||
@@ -725,6 +768,9 @@ type dhwTransfer struct {
|
|||||||
param uint32
|
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
|
// dhwTransferEOL is a sentinel value used to indicate the final node in a
|
||||||
// linked list of transfer descriptors.
|
// linked list of transfer descriptors.
|
||||||
var dhwTransferEOL = (*dhwTransfer)(unsafe.Pointer(uintptr(1)))
|
var dhwTransferEOL = (*dhwTransfer)(unsafe.Pointer(uintptr(1)))
|
||||||
@@ -744,6 +790,8 @@ func (d *dhw) transferControl() (dat, ack *dhwTransfer) {
|
|||||||
switch d.cc.id {
|
switch d.cc.id {
|
||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM:
|
||||||
return descCDCACM[d.cc.config-1].cd, descCDCACM[d.cc.config-1].ad
|
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:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -753,7 +801,9 @@ func (d *dhw) transferPrepare(
|
|||||||
transfer *dhwTransfer, data *uint8, size uint16, param uint32) {
|
transfer *dhwTransfer, data *uint8, size uint16, param uint32) {
|
||||||
|
|
||||||
transfer.next = dhwTransferEOL
|
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))
|
addr := uintptr(unsafe.Pointer(data))
|
||||||
for i := range transfer.pointer {
|
for i := range transfer.pointer {
|
||||||
transfer.pointer[i] = addr + uintptr(i)*4096
|
transfer.pointer[i] = addr + uintptr(i)*4096
|
||||||
@@ -794,6 +844,10 @@ endTransfer:
|
|||||||
arm.EnableInterrupts(ivm)
|
arm.EnableInterrupts(ivm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// General-Purpose (GP) Timer
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
func (d *dhw) timerConfigure(timer int, usec uint32, fn func()) {
|
func (d *dhw) timerConfigure(timer int, usec uint32, fn func()) {
|
||||||
if timer < 0 || timer >= len(d.timerInterrupt) {
|
if timer < 0 || timer >= len(d.timerInterrupt) {
|
||||||
return
|
return
|
||||||
@@ -831,9 +885,15 @@ func (d *dhw) timerStop(timer int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// [CDC-ACM] Serial UART (Virtual COM Port)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
func (d *dhw) uartConfigure() {
|
func (d *dhw) uartConfigure() {
|
||||||
|
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
switch d.controlBusSpeed() {
|
|
||||||
|
switch d.speed() {
|
||||||
case descDeviceSpeedHigh:
|
case descDeviceSpeedHigh:
|
||||||
acm.rxSize = descCDCACMDataRxHSPacketSize
|
acm.rxSize = descCDCACMDataRxHSPacketSize
|
||||||
acm.txSize = descCDCACMDataTxHSPacketSize
|
acm.txSize = descCDCACMDataTxHSPacketSize
|
||||||
@@ -843,6 +903,7 @@ func (d *dhw) uartConfigure() {
|
|||||||
}
|
}
|
||||||
acm.txHead = 0
|
acm.txHead = 0
|
||||||
acm.txFree = 0
|
acm.txFree = 0
|
||||||
|
acm.txPrev = false
|
||||||
acm.rxHead = 0
|
acm.rxHead = 0
|
||||||
acm.rxTail = 0
|
acm.rxTail = 0
|
||||||
acm.rxFree = 0
|
acm.rxFree = 0
|
||||||
@@ -855,7 +916,7 @@ func (d *dhw) uartConfigure() {
|
|||||||
false, descCDCACMConfigAttrDataTx)
|
false, descCDCACMConfigAttrDataTx)
|
||||||
|
|
||||||
d.endpointConfigureTx(descCDCACMEndpointStatus,
|
d.endpointConfigureTx(descCDCACMEndpointStatus,
|
||||||
acm.cxSize, false, nil)
|
acm.sxSize, false, nil)
|
||||||
d.endpointConfigureRx(descCDCACMEndpointDataRx,
|
d.endpointConfigureRx(descCDCACMEndpointDataRx,
|
||||||
acm.rxSize, false, d.uartNotify)
|
acm.rxSize, false, d.uartNotify)
|
||||||
d.endpointConfigureTx(descCDCACMEndpointDataTx,
|
d.endpointConfigureTx(descCDCACMEndpointDataTx,
|
||||||
@@ -866,6 +927,16 @@ func (d *dhw) uartConfigure() {
|
|||||||
d.timerConfigure(0, descCDCACMTxSyncUs, d.uartSync)
|
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) {
|
func (d *dhw) uartReceive(endpoint uint8) {
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||||
@@ -1071,3 +1142,263 @@ func (d *dhw) uartSync() {
|
|||||||
}
|
}
|
||||||
acm.txFree = 0
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -11,28 +11,29 @@ var (
|
|||||||
ErrUARTWriteFailed = errors.New("USB write failure")
|
ErrUARTWriteFailed = errors.New("USB write failure")
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
// UART represents a virtual serial (UART) device emulation using the USB
|
||||||
UARTConfig struct {
|
// CDC-ACM device class driver.
|
||||||
BaudRate uint32
|
type UART struct {
|
||||||
}
|
Port int
|
||||||
|
core *core
|
||||||
|
}
|
||||||
|
|
||||||
// UART represents a virtual serial (UART) device emulation using the USB
|
type UARTConfig struct {
|
||||||
// CDC-ACM device class driver.
|
// Port is the MCU's native USB core number. If in doubt, leave it
|
||||||
UART struct {
|
// uninitialized for default (0).
|
||||||
port int // USB port (core index, e.g., 0-1)
|
Port int
|
||||||
core *core
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (uart *UART) Configure(config UARTConfig) error {
|
func (uart *UART) Configure(config UARTConfig) error {
|
||||||
|
|
||||||
if uart.port >= CoreCount || uart.port >= dcdCount {
|
if config.Port >= CoreCount || config.Port >= dcdCount {
|
||||||
return ErrUARTInvalidPort
|
return ErrUARTInvalidPort
|
||||||
}
|
}
|
||||||
|
uart.Port = config.Port
|
||||||
|
|
||||||
// verify we have a free USB port and take ownership of it
|
// verify we have a free USB port and take ownership of it
|
||||||
var st status
|
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() {
|
if !st.ok() {
|
||||||
return ErrUARTInvalidPort
|
return ErrUARTInvalidPort
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,14 +106,15 @@ type class struct {
|
|||||||
|
|
||||||
// Enumerated constants for all host/device class configurations.
|
// Enumerated constants for all host/device class configurations.
|
||||||
const (
|
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.
|
// mode returns the USB core operating mode of the receiver class c.
|
||||||
//go:inline
|
//go:inline
|
||||||
func (c class) mode() int {
|
func (c class) mode() int {
|
||||||
switch c.id {
|
switch c.id {
|
||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM, classDeviceHID:
|
||||||
return modeDevice
|
return modeDevice
|
||||||
default:
|
default:
|
||||||
return modeIdle
|
return modeIdle
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package usb
|
package usb
|
||||||
|
|
||||||
|
//go:linkname ticks runtime.ticks
|
||||||
|
func ticks() int64
|
||||||
|
|
||||||
// leU64 returns a slice containing 8 bytes from the given uint64 u.
|
// leU64 returns a slice containing 8 bytes from the given uint64 u.
|
||||||
//
|
//
|
||||||
// The returned bytes have little-endian ordering; that is, the first element
|
// 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) |
|
return ((address & descEndptAddrNumberMsk) << 1) |
|
||||||
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
|
((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
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ package usb
|
|||||||
|
|
||||||
import "device/arm"
|
import "device/arm"
|
||||||
|
|
||||||
//go:linkname ticks runtime.ticks
|
|
||||||
func ticks() int64
|
|
||||||
|
|
||||||
// udelay waits for the given number of microseconds before returning.
|
// udelay waits for the given number of microseconds before returning.
|
||||||
// We cannot use the sleep timer from this context (import cycle), but we need
|
// 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.
|
// an approximate method to spin CPU cycles for short periods of time.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"device/arm"
|
"device/arm"
|
||||||
"device/nxp"
|
"device/nxp"
|
||||||
"machine"
|
"machine"
|
||||||
|
"machine/usb"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -124,7 +125,8 @@ func initUART() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initUSB() {
|
func initUSB() {
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.HID0.Configure(usb.HIDConfig{})
|
||||||
|
// machine.UART0.Configure(usb.UARTConfig{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|||||||
Reference in New Issue
Block a user