mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +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)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ package machine
|
||||
|
||||
import (
|
||||
"device/nxp"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
@@ -103,11 +104,9 @@ func init() {
|
||||
// | USB |
|
||||
// #=====================================================#
|
||||
var (
|
||||
// USBCDC is a legacy class being retained here as temporary wrapper.
|
||||
// See godoc comments on type USBCDC struct definition for details.
|
||||
UART0 = USBCDC{
|
||||
port: 0, // USB_OTG1 (Micro-B port on Teensy 4.0/4.1)
|
||||
}
|
||||
// UART0 = usb.UART{Port: 0}
|
||||
HID0 = usb.HID{Port: 0}
|
||||
UART0 = &UART1
|
||||
)
|
||||
|
||||
// #=====================================================#
|
||||
|
||||
@@ -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
|
||||
// computed as the sum of all declared device configuration descriptors.
|
||||
const dcdCount = descCDCACMCount // + ...
|
||||
const dcdCount = descCDCACMCount + descHIDCount
|
||||
|
||||
// dcdInstance provides statically-allocated instances of each USB device
|
||||
// controller configured on this platform.
|
||||
@@ -134,7 +134,6 @@ func (d *dcd) event(ev dcdEvent) {
|
||||
case dcdStageSetup:
|
||||
case dcdStageData:
|
||||
case dcdStageStatus:
|
||||
d.controlStatus()
|
||||
case dcdStageStall:
|
||||
d.controlStall()
|
||||
}
|
||||
@@ -180,7 +179,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// SET ADDRESS (0x05):
|
||||
case descRequestStandardSetAddress:
|
||||
d.controlDeviceAddress(sup.wValue)
|
||||
d.setDeviceAddress(sup.wValue)
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
|
||||
@@ -200,6 +199,14 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
d.uartConfigure()
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.serialConfigure()
|
||||
d.keyboardConfigure()
|
||||
d.mouseConfigure()
|
||||
d.joystickConfigure()
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
@@ -225,8 +232,23 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descRequestStandardGetDescriptor:
|
||||
d.controlDescriptor(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// GET CONFIGURATION (0x08):
|
||||
case descRequestStandardGetConfiguration:
|
||||
@@ -247,8 +269,38 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descRequestStandardGetDescriptor:
|
||||
d.controlDescriptor(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descHIDRequestGetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -262,11 +314,15 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// CLEAR FEATURE (0x01):
|
||||
case descRequestStandardClearFeature:
|
||||
// TODO
|
||||
d.endpointClearFeature(uint8(sup.wIndex))
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
|
||||
// SET FEATURE (0x03):
|
||||
case descRequestStandardSetFeature:
|
||||
// TODO
|
||||
d.endpointSetFeature(uint8(sup.wIndex))
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -322,6 +378,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
d.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
||||
descCDCACMCodingSize, true)
|
||||
// CDC Line Coding packet receipt handling occurs in method
|
||||
// controlComplete().
|
||||
return dcdStageSetup
|
||||
}
|
||||
|
||||
@@ -338,11 +396,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
|
||||
// Determine interface destination of the notification
|
||||
// Determine interface destination of the request
|
||||
switch sup.wIndex {
|
||||
|
||||
// Control/status interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
|
||||
d.uartSetLineState(0 != sup.wValue&0x01, 0 != sup.wValue&0x02)
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
|
||||
@@ -369,6 +429,79 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET REPORT (0x09)
|
||||
case descHIDRequestSetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if sup.wLength <= descHIDCxCount {
|
||||
d.setup = sup
|
||||
descHID[d.cc.config-1].cx[0] = 0xE9
|
||||
d.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
|
||||
uint32(sup.wLength), true)
|
||||
return dcdStageSetup
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET IDLE (0x0A)
|
||||
case descHIDRequestSetIdle:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
idleRate := sup.wValue >> 8
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_ = idleRate
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
|
||||
// --- INTERFACE Tx (IN) ---
|
||||
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
|
||||
|
||||
// Identify which request was received
|
||||
switch sup.bRequest {
|
||||
|
||||
// HID | GET REPORT (0x01)
|
||||
case descHIDRequestGetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
reportType := uint8(sup.wValue >> 8)
|
||||
reportID := uint8(sup.wValue)
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_, _ = reportType, reportID
|
||||
d.controlReply[0] = 0
|
||||
d.controlReply[1] = 0
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&d.controlReply[0])), 2, false)
|
||||
return dcdStageSetup
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
@@ -419,15 +552,14 @@ func (d *dcd) controlComplete(status uint32) {
|
||||
case classDeviceCDCACM:
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
|
||||
// Determine interface destination of the notification
|
||||
// Determine interface destination of the request
|
||||
switch d.setup.wIndex {
|
||||
|
||||
// Control/status interface:
|
||||
// CDC-ACM Control Interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
|
||||
// Notify PHY to handle triggers like special baud rates, which
|
||||
// signal to reboot into bootloader or begin receiving OTA updates
|
||||
d.controlLineCoding(descCDCACMLineCoding{
|
||||
d.uartSetLineCoding(descCDCACMLineCoding{
|
||||
baud: packU32(acm.cx[:]),
|
||||
stopBits: acm.cx[4],
|
||||
parity: acm.cx[5],
|
||||
@@ -442,6 +574,60 @@ func (d *dcd) controlComplete(status uint32) {
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET REPORT (0x09)
|
||||
case descHIDRequestSetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch d.setup.wIndex {
|
||||
|
||||
// HID Keyboard Interface
|
||||
case descHIDInterfaceKeyboard:
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch d.setup.wValue >> 8 {
|
||||
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
if 1 == d.setup.wLength {
|
||||
hid.keyboard.led = hid.cx[0]
|
||||
d.controlTransmit(uintptr(0), 0, false)
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
// HID Serial Interface
|
||||
case descHIDInterfaceSerial:
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch d.setup.wValue >> 8 {
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if d.setup.wLength >= 4 && 0x68C245A9 == packU32(hid.cx[0:4]) {
|
||||
d.enableSOF(true, descHIDInterfaceCount)
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
@@ -455,129 +641,295 @@ func (d *dcd) controlComplete(status uint32) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dcd) controlDescriptor(sup dcdSetup) {
|
||||
func (d *dcd) controlDescriptorCDCACM(sup dcdSetup) {
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
dxn := uint8(0)
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
dxn := uint8(0)
|
||||
// Determine the type of descriptor being requested
|
||||
switch sup.wValue >> 8 {
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch sup.wValue >> 8 {
|
||||
// Device descriptor
|
||||
case descTypeDevice:
|
||||
dxn = descLengthDevice
|
||||
_ = copy(acm.dx[:], acm.device[:dxn])
|
||||
|
||||
// Device descriptor
|
||||
case descTypeDevice:
|
||||
dxn = descLengthDevice
|
||||
_ = copy(acm.dx[:], acm.device[:dxn])
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
dxn = uint8(descCDCACMConfigSize)
|
||||
_ = copy(acm.dx[:], acm.config[:dxn])
|
||||
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
dxn = uint8(descCDCACMConfigSize)
|
||||
_ = copy(acm.dx[:], acm.config[:dxn])
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if 0 == len(acm.locale) {
|
||||
break // No string descriptors defined!
|
||||
}
|
||||
var sd []uint8
|
||||
if 0 == uint8(sup.wValue) {
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if 0 == len(acm.locale) {
|
||||
break // No string descriptors defined!
|
||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||
// strings in some given language. This case (setup.wValue = [0x03]00)
|
||||
// is a string request from the host to determine what that language is.
|
||||
//
|
||||
// In subsequent string requests, the host will populate setup.wIndex
|
||||
// with the language code we return here in this string descriptor.
|
||||
//
|
||||
// This way all strings returned to the host are in the same language,
|
||||
// whatever language that may be.
|
||||
code := int(sup.wIndex)
|
||||
if code >= len(acm.locale) {
|
||||
code = 0
|
||||
}
|
||||
var sd []uint8
|
||||
if 0 == uint8(sup.wValue) {
|
||||
sd = acm.locale[code].descriptor[sup.wValue&0xFF][:]
|
||||
|
||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||
// strings in some given language. This case (setup.wValue = [0x03]00)
|
||||
// is a string request from the host to determine what that language is.
|
||||
//
|
||||
// In subsequent string requests, the host will populate setup.wIndex
|
||||
// with the language code we return here in this string descriptor.
|
||||
//
|
||||
// This way all strings returned to the host are in the same language,
|
||||
// whatever language that may be.
|
||||
code := int(sup.wIndex)
|
||||
if code >= len(acm.locale) {
|
||||
code = 0
|
||||
}
|
||||
sd = acm.locale[code].descriptor[sup.wValue&0xFF][:]
|
||||
} else {
|
||||
|
||||
} else {
|
||||
// setup.wIndex now contains a language code, which we specified in a
|
||||
// previous request (above: setup.wValue = [0x03]00). We need to locate
|
||||
// the set of strings whose language matches the language code given in
|
||||
// this new setup.wIndex.
|
||||
for code := range acm.locale {
|
||||
if sup.wIndex == acm.locale[code].language {
|
||||
// Found language, check if string descriptor at given index exists
|
||||
if int(sup.wValue&0xFF) < len(acm.locale[code].descriptor) {
|
||||
|
||||
// setup.wIndex now contains a language code, which we specified in a
|
||||
// previous request (above: setup.wValue = [0x03]00). We need to locate
|
||||
// the set of strings whose language matches the language code given in
|
||||
// this new setup.wIndex.
|
||||
for code := range acm.locale {
|
||||
if sup.wIndex == acm.locale[code].language {
|
||||
// Found language, check if string descriptor at given index exists
|
||||
if int(sup.wValue&0xFF) < len(acm.locale[code].descriptor) {
|
||||
|
||||
// Found language with a string defined at the requested index.
|
||||
//
|
||||
// TODO: Add API methods to device controller that allows the user
|
||||
// to provide these strings at/before driver initialization.
|
||||
//
|
||||
// For now, we just always use the descCommon* strings.
|
||||
var s string
|
||||
switch uint8(sup.wValue) {
|
||||
case 1:
|
||||
s = descCommonManufacturer
|
||||
case 2:
|
||||
s = descCommonProduct
|
||||
case 3:
|
||||
s = descCommonSerialNumber
|
||||
}
|
||||
|
||||
// Construct a string descriptor dynamically to be transmitted on
|
||||
// the serial bus.
|
||||
sd = acm.locale[code].descriptor[int(sup.wValue&0xFF)][:]
|
||||
// String descriptor format is 2-byte header + 2-bytes per rune
|
||||
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
|
||||
sd[1] = descTypeString // header[1] = descriptor type
|
||||
// Copy UTF-8 string into string descriptor as UTF-16
|
||||
for n, c := range s {
|
||||
if 2+2*n >= len(sd) {
|
||||
break
|
||||
}
|
||||
sd[2+2*n] = uint8(c)
|
||||
sd[3+2*n] = 0
|
||||
}
|
||||
break // end search for matching language code
|
||||
// Found language with a string defined at the requested index.
|
||||
//
|
||||
// TODO: Add API methods to device controller that allows the user
|
||||
// to provide these strings at/before driver initialization.
|
||||
//
|
||||
// For now, we just always use the descCommon* strings.
|
||||
var s string
|
||||
switch uint8(sup.wValue) {
|
||||
case 1:
|
||||
s = descCommonManufacturer
|
||||
case 2:
|
||||
s = descCommonProduct + " CDC-ACM"
|
||||
case 3:
|
||||
s = descCommonSerialNumber
|
||||
}
|
||||
|
||||
// Construct a string descriptor dynamically to be transmitted on
|
||||
// the serial bus.
|
||||
sd = acm.locale[code].descriptor[int(sup.wValue&0xFF)][:]
|
||||
// String descriptor format is 2-byte header + 2-bytes per rune
|
||||
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
|
||||
sd[1] = descTypeString // header[1] = descriptor type
|
||||
// Copy UTF-8 string into string descriptor as UTF-16
|
||||
for n, c := range s {
|
||||
if 2+2*n >= len(sd) {
|
||||
break
|
||||
}
|
||||
sd[2+2*n] = uint8(c)
|
||||
sd[3+2*n] = 0
|
||||
}
|
||||
break // end search for matching language code
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy string descriptor into descriptor transmit buffer
|
||||
if nil != sd && len(sd) >= 0 {
|
||||
dxn = sd[0]
|
||||
_ = copy(acm.dx[:], sd[:dxn])
|
||||
}
|
||||
|
||||
// Device qualification descriptor
|
||||
case descTypeQualification:
|
||||
dxn = descLengthQualification
|
||||
_ = copy(acm.dx[:], acm.qualif[:dxn])
|
||||
|
||||
// Alternate configuration descriptor
|
||||
case descTypeOtherSpeedConfiguration:
|
||||
// TODO
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
// Copy string descriptor into descriptor transmit buffer
|
||||
if nil != sd && len(sd) >= 0 {
|
||||
dxn = sd[0]
|
||||
_ = copy(acm.dx[:], sd[:dxn])
|
||||
}
|
||||
|
||||
if dxn > 0 {
|
||||
if dxn > uint8(sup.wLength) {
|
||||
dxn = uint8(sup.wLength)
|
||||
// Device qualification descriptor
|
||||
case descTypeQualification:
|
||||
dxn = descLengthQualification
|
||||
_ = copy(acm.dx[:], acm.qualif[:dxn])
|
||||
|
||||
// Alternate configuration descriptor
|
||||
case descTypeOtherSpeedConfiguration:
|
||||
// TODO
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
if dxn > 0 {
|
||||
if dxn > uint8(sup.wLength) {
|
||||
dxn = uint8(sup.wLength)
|
||||
}
|
||||
flushCache(
|
||||
uintptr(unsafe.Pointer(&acm.dx[0])), uintptr(dxn))
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&acm.dx[0])), uint32(dxn), false)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dcd) controlDescriptorHID(sup dcdSetup) {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
dxn := uint8(0)
|
||||
pos := uint8(0)
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch sup.wValue >> 8 {
|
||||
|
||||
// Device descriptor
|
||||
case descTypeDevice:
|
||||
dxn = descLengthDevice
|
||||
_ = copy(hid.dx[:], hid.device[:dxn])
|
||||
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
dxn = uint8(descHIDConfigSize)
|
||||
_ = copy(hid.dx[:], hid.config[:dxn])
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if 0 == len(hid.locale) {
|
||||
break // No string descriptors defined!
|
||||
}
|
||||
var sd []uint8
|
||||
if 0 == uint8(sup.wValue) {
|
||||
|
||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||
// strings in some given language. This case (setup.wValue = [0x03]00)
|
||||
// is a string request from the host to determine what that language is.
|
||||
//
|
||||
// In subsequent string requests, the host will populate setup.wIndex
|
||||
// with the language code we return here in this string descriptor.
|
||||
//
|
||||
// This way all strings returned to the host are in the same language,
|
||||
// whatever language that may be.
|
||||
code := int(sup.wIndex)
|
||||
if code >= len(hid.locale) {
|
||||
code = 0
|
||||
}
|
||||
flushCache(
|
||||
uintptr(unsafe.Pointer(&acm.dx[0])), uintptr(dxn))
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&acm.dx[0])), uint32(dxn), false)
|
||||
sd = hid.locale[code].descriptor[sup.wValue&0xFF][:]
|
||||
|
||||
} else {
|
||||
|
||||
// setup.wIndex now contains a language code, which we specified in a
|
||||
// previous request (above: setup.wValue = [0x03]00). We need to locate
|
||||
// the set of strings whose language matches the language code given in
|
||||
// this new setup.wIndex.
|
||||
for code := range hid.locale {
|
||||
if sup.wIndex == hid.locale[code].language {
|
||||
// Found language, check if string descriptor at given index exists
|
||||
if int(sup.wValue&0xFF) < len(hid.locale[code].descriptor) {
|
||||
|
||||
// Found language with a string defined at the requested index.
|
||||
//
|
||||
// TODO: Add API methods to device controller that allows the user
|
||||
// to provide these strings at/before driver initialization.
|
||||
//
|
||||
// For now, we just always use the descCommon* strings.
|
||||
var s string
|
||||
switch uint8(sup.wValue) {
|
||||
case 1:
|
||||
s = descCommonManufacturer
|
||||
case 2:
|
||||
s = descCommonProduct + " HID"
|
||||
case 3:
|
||||
s = descCommonSerialNumber
|
||||
}
|
||||
|
||||
// Construct a string descriptor dynamically to be transmitted on
|
||||
// the serial bus.
|
||||
sd = hid.locale[code].descriptor[int(sup.wValue&0xFF)][:]
|
||||
// String descriptor format is 2-byte header + 2-bytes per rune
|
||||
sd[0] = uint8(2 + 2*len(s)) // header[0] = descriptor length
|
||||
sd[1] = descTypeString // header[1] = descriptor type
|
||||
// Copy UTF-8 string into string descriptor as UTF-16
|
||||
for n, c := range s {
|
||||
if 2+2*n >= len(sd) {
|
||||
break
|
||||
}
|
||||
sd[2+2*n] = uint8(c)
|
||||
sd[3+2*n] = 0
|
||||
}
|
||||
break // end search for matching language code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy string descriptor into descriptor transmit buffer
|
||||
if nil != sd && len(sd) >= 0 {
|
||||
dxn = sd[0]
|
||||
_ = copy(hid.dx[:], sd[:dxn])
|
||||
}
|
||||
|
||||
// Device qualification descriptor
|
||||
case descTypeQualification:
|
||||
dxn = descLengthQualification
|
||||
_ = copy(hid.dx[:], hid.qualif[:dxn])
|
||||
|
||||
// Alternate configuration descriptor
|
||||
case descTypeOtherSpeedConfiguration:
|
||||
// TODO
|
||||
|
||||
// HID descriptor
|
||||
case descTypeHID:
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch sup.wIndex {
|
||||
case descHIDInterfaceKeyboard:
|
||||
pos = descHIDConfigKeyboardPos
|
||||
|
||||
case descHIDInterfaceMouse:
|
||||
pos = descHIDConfigMousePos
|
||||
|
||||
case descHIDInterfaceSerial:
|
||||
pos = descHIDConfigSerialPos
|
||||
|
||||
case descHIDInterfaceJoystick:
|
||||
pos = descHIDConfigJoystickPos
|
||||
|
||||
case descHIDInterfaceMediaKey:
|
||||
pos = descHIDConfigMediaKeyPos
|
||||
|
||||
default:
|
||||
// Unhandled HID interface
|
||||
}
|
||||
|
||||
if 0 != pos {
|
||||
dxn = descLengthInterface
|
||||
_ = copy(hid.dx[:], hid.config[pos:pos+dxn])
|
||||
}
|
||||
|
||||
// HID report descriptor
|
||||
case descTypeHIDReport:
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch sup.wIndex {
|
||||
case descHIDInterfaceKeyboard:
|
||||
dxn = uint8(len(descHIDReportKeyboard))
|
||||
_ = copy(hid.dx[:], descHIDReportKeyboard[:])
|
||||
|
||||
case descHIDInterfaceMouse:
|
||||
dxn = uint8(len(descHIDReportMouse))
|
||||
_ = copy(hid.dx[:], descHIDReportMouse[:])
|
||||
|
||||
case descHIDInterfaceSerial:
|
||||
dxn = uint8(len(descHIDReportSerial))
|
||||
_ = copy(hid.dx[:], descHIDReportSerial[:])
|
||||
|
||||
case descHIDInterfaceJoystick:
|
||||
dxn = uint8(len(descHIDReportJoystick))
|
||||
_ = copy(hid.dx[:], descHIDReportJoystick[:])
|
||||
|
||||
case descHIDInterfaceMediaKey:
|
||||
dxn = uint8(len(descHIDReportMediaKey))
|
||||
_ = copy(hid.dx[:], descHIDReportMediaKey[:])
|
||||
|
||||
default:
|
||||
// Unhandled HID interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
if dxn > 0 {
|
||||
if dxn > uint8(sup.wLength) {
|
||||
dxn = uint8(sup.wLength)
|
||||
}
|
||||
flushCache(
|
||||
uintptr(unsafe.Pointer(&hid.dx[0])), uintptr(dxn))
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&hid.dx[0])), uint32(dxn), false)
|
||||
}
|
||||
}
|
||||
|
||||
+662
-179
@@ -304,152 +304,75 @@ const (
|
||||
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
|
||||
)
|
||||
|
||||
// descCDCACM0Device holds the default device descriptor for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0Device = [descLengthDevice]uint8{
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
descCDCTypeComm, // Class code (assigned by the USB-IF).
|
||||
descCDCSubNone, // Subclass code (assigned by the USB-IF).
|
||||
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
}
|
||||
// USB HID constants defined per specification
|
||||
const (
|
||||
// HID class
|
||||
descHIDType = 0x03
|
||||
|
||||
// descCDCACM0Qualif holds the default device qualification descriptor for
|
||||
// CDC-ACM[0], i.e., configuration index 1.
|
||||
var descCDCACM0Qualif = [descLengthQualification]uint8{
|
||||
descLengthQualification, // Size of this descriptor in bytes
|
||||
descTypeQualification, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
descCDCTypeComm, // Class code (assigned by the USB-IF).
|
||||
descCDCSubNone, // Subclass code (assigned by the USB-IF).
|
||||
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
0, // Reserved
|
||||
}
|
||||
// HID subclass
|
||||
descHIDSubNone = 0x00
|
||||
descHIDSubBoot = 0x01
|
||||
|
||||
// HID protocol
|
||||
descHIDProtoNone = 0x00
|
||||
descHIDProtoKeyboard = 0x01
|
||||
descHIDProtoMouse = 0x02
|
||||
|
||||
descHIDRequestGetReport = 0x01 // HID request GET_REPORT
|
||||
descHIDRequestGetReportTypeInput = 0x01 // HID request GET_REPORT type INPUT
|
||||
descHIDRequestGetReportTypeOutput = 0x02 // HID request GET_REPORT type OUTPUT
|
||||
descHIDRequestGetReportTypeFeature = 0x03 // HID request GET_REPORT type FEATURE
|
||||
descHIDRequestGetIdle = 0x02 // HID request GET_IDLE
|
||||
descHIDRequestGetProtocol = 0x03 // HID request GET_PROTOCOL
|
||||
descHIDRequestSetReport = 0x09 // HID request SET_REPORT
|
||||
descHIDRequestSetIdle = 0x0A // HID request SET_IDLE
|
||||
descHIDRequestSetProtocol = 0x0B // HID request SET_PROTOCOL
|
||||
)
|
||||
|
||||
const (
|
||||
// Size of all CDC-ACM configuration descriptors.
|
||||
descCDCACMConfigSize = uint16(
|
||||
descLengthConfigure + // configuration
|
||||
descLengthInterface + // communication/control interface
|
||||
descCDCFuncLengthHeader + // CDC header
|
||||
descCDCFuncLengthCallManagement + // CDC call management
|
||||
descCDCFuncLengthAbstractControl + // CDC abstract control
|
||||
descCDCFuncLengthUnion + // CDC union
|
||||
descLengthEndpoint + // communication/control input endpoint
|
||||
descLengthInterface + // data interface
|
||||
descLengthEndpoint + // data input endpoint
|
||||
descLengthEndpoint) // data output endpoint
|
||||
descLengthConfigure + // Configuration Header
|
||||
descLengthInterface + // CDC Interface Descriptor
|
||||
descCDCFuncLengthHeader + // CDC Header
|
||||
descCDCFuncLengthCallManagement + // CDC Call Management Func Descriptor
|
||||
descCDCFuncLengthAbstractControl + // CDC Abstract Control Func Descriptor
|
||||
descCDCFuncLengthUnion + // CDC Union Functional Descriptor
|
||||
descLengthEndpoint + // CDC Status IN Endpoint Descriptor
|
||||
descLengthInterface + // CDC Data Interface Descriptor
|
||||
descLengthEndpoint + // CDC Data IN Endpoint Descriptor
|
||||
descLengthEndpoint) // CDC Data OUT Endpoint Descriptor
|
||||
|
||||
// Size of all HID configuration descriptors.
|
||||
descHIDConfigSize = uint16(
|
||||
descLengthConfigure + // Configuration Header
|
||||
descLengthInterface + // Keyboard Interface Descriptor
|
||||
descLengthInterface + // Keyboard HID Interface Descriptor
|
||||
descLengthEndpoint + // Keyboard Endpoint Descriptor
|
||||
descLengthInterface + // Mouse Interface Descriptor
|
||||
descLengthInterface + // Mouse HID Interface Descriptor
|
||||
descLengthEndpoint + // Mouse Endpoint Descriptor
|
||||
descLengthInterface + // Serial Interface Descriptor
|
||||
descLengthInterface + // Serial HID Interface Descriptor
|
||||
descLengthEndpoint + // Serial Endpoint Descriptor
|
||||
descLengthEndpoint +
|
||||
descLengthInterface + // Joystick Interface Descriptor
|
||||
descLengthInterface + // Joystick HID Interface Descriptor
|
||||
descLengthEndpoint + // Joystick Endpoint Descriptor
|
||||
descLengthInterface + // Keyboard Media Keys Interface Descriptor
|
||||
descLengthInterface + // Keyboard Media Keys HID Interface Descriptor
|
||||
descLengthEndpoint) // Keyboard Media Keys Endpoint Descriptor
|
||||
|
||||
// Position of each HID interface descriptor as offsets into the configuration
|
||||
// descriptor. See comments in the configuration descriptor definition for the
|
||||
// incremental tally that computes these.
|
||||
descHIDConfigKeyboardPos = 18
|
||||
descHIDConfigMousePos = 43
|
||||
descHIDConfigSerialPos = 68
|
||||
descHIDConfigJoystickPos = 100
|
||||
descHIDConfigMediaKeyPos = 125
|
||||
)
|
||||
|
||||
// descCDCACM0Config holds the default configuration descriptors for CDC-ACM[0],
|
||||
// i.e., configuration index 1.
|
||||
var descCDCACM0Config = [descCDCACMConfigSize]uint8{
|
||||
descLengthConfigure, // Size of this descriptor in bytes
|
||||
descTypeConfigure, // Descriptor Type
|
||||
lsU8(descCDCACMConfigSize), // Total length of data returned for this configuration (low)
|
||||
msU8(descCDCACMConfigSize), // Total length of data returned for this configuration (high)
|
||||
descCDCACMInterfaceCount, // Number of interfaces supported by this configuration
|
||||
1, // Value to use to select this configuration (1 = CDC-ACM[0])
|
||||
0, // Index of string descriptor describing this configuration
|
||||
descEndptConfigAttr, // Configuration attributes
|
||||
descCDCACMMaxPower, // Max power consumption when fully-operational (2 mA units)
|
||||
|
||||
// Communication/Control Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descCDCACMInterfaceCtrl, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descCDCTypeComm, // Class code
|
||||
descCDCSubAbstractControl, // Subclass code
|
||||
descCDCProtoNone, // Protocol code (NOTE: Teensyduino defines this as 1 [AT V.250])
|
||||
0, // Interface Description String Index
|
||||
|
||||
// CDC Header Functional Descriptor
|
||||
descCDCFuncLengthHeader, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeHeader, // Descriptor Subtype
|
||||
0x10, // USB CDC specification version 1.10 (low)
|
||||
0x01, // USB CDC specification version 1.10 (high)
|
||||
|
||||
// CDC Call Management Functional Descriptor
|
||||
descCDCFuncLengthCallManagement, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeCallManagement, // Descriptor Subtype
|
||||
0x01, // Capabilities
|
||||
descCDCACMInterfaceData, // Data Interface
|
||||
|
||||
// CDC Abstract Control Management Functional Descriptor
|
||||
descCDCFuncLengthAbstractControl, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeAbstractControl, // Descriptor Subtype
|
||||
0x06, // Capabilities
|
||||
|
||||
// CDC Union Functional Descriptor
|
||||
descCDCFuncLengthUnion, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeUnion, // Descriptor Subtype
|
||||
descCDCACMInterfaceCtrl, // Controlling interface index
|
||||
descCDCACMInterfaceData, // Controlled interface index
|
||||
|
||||
// Communication/Control Notification Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointStatus | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descCDCACMStatusPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMStatusPacketSize), // Max packet size (high)
|
||||
16, // Polling Interval
|
||||
|
||||
// Data Interface Descriptor
|
||||
descLengthInterface, // Interface length
|
||||
descTypeInterface, // Interface type
|
||||
descCDCACMInterfaceData, // Interface index
|
||||
0, // Alternate setting
|
||||
2, // Number of endpoints
|
||||
descCDCTypeData, // Class code
|
||||
descCDCSubNone, // Subclass code
|
||||
descCDCProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// Data Bulk Rx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataRx | // Endpoint address
|
||||
descEndptAddrDirectionOut,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataRxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataRxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
|
||||
// Data Bulk Tx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataTx | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataTxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataTxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
}
|
||||
|
||||
type (
|
||||
// descString is the actual byte array used to hold string descriptors. The
|
||||
// first two bytes are a USB-specified header (0=length, 1=type), and the
|
||||
@@ -479,28 +402,6 @@ const (
|
||||
// for each string) seems a good compromise.
|
||||
)
|
||||
|
||||
// descCDCACM0String holds the default string descriptors for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0String = [descCDCACMLanguageCount]descStringLanguage{
|
||||
|
||||
{ // [0x0409] US English
|
||||
language: descLanguageEnglish,
|
||||
descriptor: descStringIndex{
|
||||
{ /* [0] Language */
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
// Actual string descriptors (index > 0) are copied into here at runtime!
|
||||
// This allows for application- or even user-defined string descriptors.
|
||||
{ /* [1] Manufacturer */ },
|
||||
{ /* [2] Product */ },
|
||||
{ /* [3] Serial Number */ },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
|
||||
const descCDCACMCodingSize = 7
|
||||
|
||||
@@ -514,23 +415,19 @@ type descCDCACMLineCoding struct {
|
||||
|
||||
// Common configuration constants for the USB CDC-ACM (single) device class.
|
||||
const (
|
||||
// String descriptor languages available
|
||||
descCDCACMLanguageCount = 1
|
||||
descCDCACMLanguageCount = 1 // String descriptor languages available
|
||||
|
||||
// Interfaces for all CDC-ACM configurations.
|
||||
descCDCACMInterfaceCount = 2
|
||||
descCDCACMInterfaceCtrl = 0
|
||||
descCDCACMInterfaceData = 1
|
||||
descCDCACMInterfaceCount = 2 // Interfaces for all CDC-ACM configurations.
|
||||
descCDCACMEndpointCount = 4 // Endpoints for all CDC-ACM configurations.
|
||||
|
||||
// Endpoints for all CDC-ACM configurations.
|
||||
descCDCACMEndpointCount = 4
|
||||
descCDCACMEndpointStatus = 2 // Communication/control interrupt input
|
||||
descCDCACMEndpointDataRx = 3 // Bulk data output
|
||||
descCDCACMEndpointDataTx = 4 // Bulk data input
|
||||
|
||||
// Endpoint configuration attributes for all CDC-ACM configurations.
|
||||
descCDCACMInterfaceCtrl = 0 // CDC-ACM Control Interface
|
||||
descCDCACMEndpointStatus = 2 // CDC-ACM Interrupt IN Endpoint
|
||||
descCDCACMConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
|
||||
|
||||
descCDCACMInterfaceData = 1 // CDC-ACM Data Interface
|
||||
descCDCACMEndpointDataRx = 3 // CDC-ACM Bulk Data OUT (Rx) Endpoint
|
||||
descCDCACMConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
|
||||
descCDCACMEndpointDataTx = 4 // CDC-ACM Bulk Data IN (Tx) Endpoint
|
||||
descCDCACMConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
|
||||
)
|
||||
|
||||
@@ -547,14 +444,600 @@ type descCDCACMClass struct {
|
||||
|
||||
// descCDCACM holds statically-allocated instances for each of the CDC-ACM
|
||||
// (single) device class configurations, ordered by index (offset by -1).
|
||||
var descCDCACM = [descCDCACMCount]descCDCACMClass{
|
||||
var descCDCACM = [dcdCount]descCDCACMClass{
|
||||
|
||||
{ // CDC-ACM (single) class configuration index 1
|
||||
descCDCACMClassData: &descCDCACMData[0],
|
||||
|
||||
locale: &descCDCACM0String,
|
||||
device: &descCDCACM0Device,
|
||||
qualif: &descCDCACM0Qualif,
|
||||
config: &descCDCACM0Config,
|
||||
locale: &[descCDCACMLanguageCount]descStringLanguage{
|
||||
|
||||
{ // [0x0409] US English
|
||||
language: descLanguageEnglish,
|
||||
descriptor: descStringIndex{
|
||||
{ /* [0] Language */
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
// Actual string descriptors (index > 0) are copied into here at runtime!
|
||||
// This allows for application- or even user-defined string descriptors.
|
||||
{ /* [1] Manufacturer */ },
|
||||
{ /* [2] Product */ },
|
||||
{ /* [3] Serial Number */ },
|
||||
},
|
||||
},
|
||||
},
|
||||
device: &[descLengthDevice]uint8{
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
},
|
||||
qualif: &[descLengthQualification]uint8{
|
||||
descLengthQualification, // Size of this descriptor in bytes
|
||||
descTypeQualification, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
0, // Reserved
|
||||
},
|
||||
config: &[descCDCACMConfigSize]uint8{
|
||||
descLengthConfigure, // Size of this descriptor in bytes
|
||||
descTypeConfigure, // Descriptor Type
|
||||
lsU8(descCDCACMConfigSize), // Total length of data returned for this configuration (low)
|
||||
msU8(descCDCACMConfigSize), // Total length of data returned for this configuration (high)
|
||||
descCDCACMInterfaceCount, // Number of interfaces supported by this configuration
|
||||
1, // Value to use to select this configuration (1 = CDC-ACM[0])
|
||||
0, // Index of string descriptor describing this configuration
|
||||
descEndptConfigAttr, // Configuration attributes
|
||||
descCDCACMMaxPower, // Max power consumption when fully-operational (2 mA units)
|
||||
|
||||
// Communication/Control Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descCDCACMInterfaceCtrl, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descCDCTypeComm, // Class code
|
||||
descCDCSubAbstractControl, // Subclass code
|
||||
descCDCProtoNone, // Protocol code (NOTE: Teensyduino defines this as 1 [AT V.250])
|
||||
0, // Interface Description String Index
|
||||
|
||||
// CDC Header Functional Descriptor
|
||||
descCDCFuncLengthHeader, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeHeader, // Descriptor Subtype
|
||||
0x10, // USB CDC specification version 1.10 (low)
|
||||
0x01, // USB CDC specification version 1.10 (high)
|
||||
|
||||
// CDC Call Management Functional Descriptor
|
||||
descCDCFuncLengthCallManagement, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeCallManagement, // Descriptor Subtype
|
||||
0x01, // Capabilities
|
||||
descCDCACMInterfaceData, // Data Interface
|
||||
|
||||
// CDC Abstract Control Management Functional Descriptor
|
||||
descCDCFuncLengthAbstractControl, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeAbstractControl, // Descriptor Subtype
|
||||
0x06, // Capabilities
|
||||
|
||||
// CDC Union Functional Descriptor
|
||||
descCDCFuncLengthUnion, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeUnion, // Descriptor Subtype
|
||||
descCDCACMInterfaceCtrl, // Controlling interface index
|
||||
descCDCACMInterfaceData, // Controlled interface index
|
||||
|
||||
// Communication/Control Notification Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointStatus | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descCDCACMStatusPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMStatusPacketSize), // Max packet size (high)
|
||||
descCDCACMStatusInterval, // Polling Interval
|
||||
|
||||
// Data Interface Descriptor
|
||||
descLengthInterface, // Interface length
|
||||
descTypeInterface, // Interface type
|
||||
descCDCACMInterfaceData, // Interface index
|
||||
0, // Alternate setting
|
||||
2, // Number of endpoints
|
||||
descCDCTypeData, // Class code
|
||||
descCDCSubNone, // Subclass code
|
||||
descCDCProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// Data Bulk Rx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataRx | // Endpoint address
|
||||
descEndptAddrDirectionOut,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataRxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataRxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
|
||||
// Data Bulk Tx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataTx | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataTxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataTxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Common configuration constants for the USB HID device class.
|
||||
const (
|
||||
descHIDLanguageCount = 1 // String descriptor languages available
|
||||
|
||||
descHIDInterfaceCount = 5 // Interfaces for all HID configurations.
|
||||
descHIDEndpointCount = 6 // Endpoints for all HID configurations.
|
||||
|
||||
descHIDInterfaceKeyboard = 0 // HID Keyboard Interface
|
||||
descHIDEndpointKeyboard = 3 // HID Keyboard IN Endpoint
|
||||
descHIDConfigAttrKeyboard = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
|
||||
|
||||
descHIDInterfaceMouse = 1 // HID Mouse Interface
|
||||
descHIDEndpointMouse = 5 // HID Mouse IN Endpoint
|
||||
descHIDConfigAttrMouse = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
|
||||
|
||||
descHIDInterfaceSerial = 2 // HID Serial (UART emulation) Interface
|
||||
descHIDEndpointSerialRx = 2 // HID Serial OUT (Rx) Endpoint
|
||||
descHIDEndpointSerialTx = 2 // HID Serial IN (Tx) Endpoint
|
||||
descHIDConfigAttrSerial = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxInterrupt
|
||||
|
||||
descHIDInterfaceJoystick = 3 // HID Joystick Interface
|
||||
descHIDEndpointJoystick = 6 // HID Joystick IN Endpoint
|
||||
descHIDConfigAttrJoystick = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
|
||||
|
||||
descHIDInterfaceMediaKey = 4 // HID Keyboard Media Keys Interface
|
||||
descHIDEndpointMediaKey = 4 // HID Keyboard Media Keys IN Endpoint
|
||||
descHIDConfigAttrMediaKey = descEndptConfigAttrTxInterrupt | descEndptConfigAttrRxUnused
|
||||
)
|
||||
|
||||
// descHIDClass holds references to all descriptors, buffers, and control
|
||||
// structures for the USB HID device class.
|
||||
type descHIDClass struct {
|
||||
*descHIDClassData // Target-defined, class-specific data
|
||||
|
||||
locale *[descHIDLanguageCount]descStringLanguage // string descriptors
|
||||
device *[descLengthDevice]uint8 // device descriptor
|
||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||
config *[descHIDConfigSize]uint8 // configuration descriptor
|
||||
}
|
||||
|
||||
// descHID holds statically-allocated instances for each of the HID device class
|
||||
// configurations, ordered by index (offset by -1).
|
||||
var descHID = [dcdCount]descHIDClass{
|
||||
|
||||
{ // HID class configuration index 1
|
||||
descHIDClassData: &descHIDData[0],
|
||||
|
||||
locale: &[descHIDLanguageCount]descStringLanguage{
|
||||
|
||||
{ // [0x0409] US English
|
||||
language: descLanguageEnglish,
|
||||
descriptor: descStringIndex{
|
||||
{ /* [0] Language */
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
// Actual string descriptors (index > 0) are copied into here at runtime!
|
||||
// This allows for application- or even user-defined string descriptors.
|
||||
{ /* [1] Manufacturer */ },
|
||||
{ /* [2] Product */ },
|
||||
{ /* [3] Serial Number */ },
|
||||
},
|
||||
},
|
||||
},
|
||||
device: &[descLengthDevice]uint8{
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descHIDCount, // Number of possible configurations
|
||||
},
|
||||
qualif: &[descLengthQualification]uint8{
|
||||
descLengthQualification, // Size of this descriptor in bytes
|
||||
descTypeQualification, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
descHIDCount, // Number of possible configurations
|
||||
0, // Reserved
|
||||
},
|
||||
config: &[descHIDConfigSize]uint8{
|
||||
// [0+9]
|
||||
descLengthConfigure, // Size of this descriptor in bytes
|
||||
descTypeConfigure, // Descriptor Type
|
||||
lsU8(descHIDConfigSize), // Total length of data returned for this configuration (low)
|
||||
msU8(descHIDConfigSize), // Total length of data returned for this configuration (high)
|
||||
descHIDInterfaceCount, // Number of interfaces supported by this configuration
|
||||
1, // Value to use to select this configuration (1 = CDC-ACM[0])
|
||||
0, // Index of string descriptor describing this configuration
|
||||
descEndptConfigAttr, // Configuration attributes
|
||||
descHIDMaxPower, // Max power consumption when fully-operational (2 mA units)
|
||||
|
||||
// [9+9] Keyboard Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descHIDInterfaceKeyboard, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descHIDType, // Class code (HID = 0x03)
|
||||
descHIDSubBoot, // Subclass code (Boot = 0x01)
|
||||
descHIDProtoKeyboard, // Protocol code (Keyboard = 0x01)
|
||||
0, // Interface Description String Index
|
||||
|
||||
// [18+9] Keyboard HID Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeHID, // Descriptor type
|
||||
0x11, // HID BCD (low)
|
||||
0x01, // HID BCD (high)
|
||||
0, // Country code
|
||||
1, // Number of descriptors
|
||||
descTypeHIDReport, // Descriptor type
|
||||
lsU8(uint16(len(descHIDReportKeyboard))), // Descriptor length (low)
|
||||
msU8(uint16(len(descHIDReportKeyboard))), // Descriptor length (high)
|
||||
|
||||
// [27+7] Keyboard Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointKeyboard | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDKeyboardTxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDKeyboardTxPacketSize), // Max packet size (high)
|
||||
descHIDKeyboardTxInterval, // Polling Interval
|
||||
|
||||
// [34+9] Mouse Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descHIDInterfaceMouse, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descHIDType, // Class code (HID = 0x03)
|
||||
descHIDSubBoot, // Subclass code (Boot = 0x01)
|
||||
descHIDProtoMouse, // Protocol code (Mouse = 0x02)
|
||||
0, // Interface Description String Index
|
||||
|
||||
// [43+9] Mouse HID Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeHID, // Descriptor type
|
||||
0x11, // HID BCD (low)
|
||||
0x01, // HID BCD (high)
|
||||
0, // Country code
|
||||
1, // Number of descriptors
|
||||
descTypeHIDReport, // Descriptor type
|
||||
lsU8(uint16(len(descHIDReportMouse))), // Descriptor length (low)
|
||||
msU8(uint16(len(descHIDReportMouse))), // Descriptor length (high)
|
||||
|
||||
// [52+7] Mouse Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointMouse | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDMouseTxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDMouseTxPacketSize), // Max packet size (high)
|
||||
descHIDMouseTxInterval, // Polling Interval
|
||||
|
||||
// [59+9] Serial Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descHIDInterfaceSerial, // Interface index
|
||||
0, // Alternate setting
|
||||
2, // Number of endpoints
|
||||
descHIDType, // Class code (HID = 0x03)
|
||||
descHIDSubNone, // Subclass code
|
||||
descHIDProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// [68+9] Serial HID Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeHID, // Descriptor type
|
||||
0x11, // HID BCD (low)
|
||||
0x01, // HID BCD (high)
|
||||
0, // Country code
|
||||
1, // Number of descriptors
|
||||
descTypeHIDReport, // Descriptor type
|
||||
lsU8(uint16(len(descHIDReportSerial))), // Descriptor length (low)
|
||||
msU8(uint16(len(descHIDReportSerial))), // Descriptor length (high)
|
||||
|
||||
// [77+7] Serial Tx Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointSerialTx | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDSerialTxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDSerialTxPacketSize), // Max packet size (high)
|
||||
descHIDSerialTxInterval, // Polling Interval
|
||||
|
||||
// [84+7] Serial Rx Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointSerialRx | // Endpoint address
|
||||
descEndptAddrDirectionOut,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDSerialRxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDSerialRxPacketSize), // Max packet size (high)
|
||||
descHIDSerialRxInterval, // Polling Interval
|
||||
|
||||
// [91+9] Joystick Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descHIDInterfaceJoystick, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descHIDType, // Class code (HID = 0x03)
|
||||
descHIDSubNone, // Subclass code
|
||||
descHIDProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// [100+9] Joystick HID Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeHID, // Descriptor type
|
||||
0x11, // HID BCD (low)
|
||||
0x01, // HID BCD (high)
|
||||
0, // Country code
|
||||
1, // Number of descriptors
|
||||
descTypeHIDReport, // Descriptor type
|
||||
lsU8(uint16(len(descHIDReportJoystick))), // Descriptor length (low)
|
||||
msU8(uint16(len(descHIDReportJoystick))), // Descriptor length (high)
|
||||
|
||||
// [109+7] Joystick Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointJoystick | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDJoystickTxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDJoystickTxPacketSize), // Max packet size (high)
|
||||
descHIDJoystickTxInterval, // Polling Interval
|
||||
|
||||
// [116+9] Keyboard Media Keys Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descHIDInterfaceMediaKey, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descHIDType, // Class code (HID = 0x03)
|
||||
descHIDSubNone, // Subclass code
|
||||
descHIDProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// [125+9] Keyboard Media Keys HID Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeHID, // Descriptor type
|
||||
0x11, // HID BCD (low)
|
||||
0x01, // HID BCD (high)
|
||||
0, // Country code
|
||||
1, // Number of descriptors
|
||||
descTypeHIDReport, // Descriptor type
|
||||
lsU8(uint16(len(descHIDReportMediaKey))), // Descriptor length (low)
|
||||
msU8(uint16(len(descHIDReportMediaKey))), // Descriptor length (high)
|
||||
|
||||
// [134+7] Keyboard Media Keys Endpoint Descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descHIDEndpointMediaKey | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descHIDMediaKeyTxPacketSize), // Max packet size (low)
|
||||
msU8(descHIDMediaKeyTxPacketSize), // Max packet size (high)
|
||||
descHIDMediaKeyTxInterval, // Polling Interval
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var descHIDReportSerial = [...]uint8{
|
||||
0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
|
||||
0x09, 0x04, // Usage 0x04
|
||||
0xA1, 0x5C, // Collection 0x5C
|
||||
0x75, 0x08, // report size = 8 bits (global)
|
||||
0x15, 0x00, // logical minimum = 0 (global)
|
||||
0x26, 0xFF, 0x00, // logical maximum = 255 (global)
|
||||
0x95, descHIDSerialTxPacketSize, // report count (global)
|
||||
0x09, 0x75, // usage (local)
|
||||
0x81, 0x02, // Input
|
||||
0x95, descHIDSerialRxPacketSize, // report count (global)
|
||||
0x09, 0x76, // usage (local)
|
||||
0x91, 0x02, // Output
|
||||
0x95, 0x04, // report count (global)
|
||||
0x09, 0x76, // usage (local)
|
||||
0xB1, 0x02, // Feature
|
||||
0xC0, // end collection
|
||||
}
|
||||
|
||||
var descHIDReportKeyboard = [...]uint8{
|
||||
0x05, 0x01, // Usage Page (Generic Desktop),
|
||||
0x09, 0x06, // Usage (Keyboard),
|
||||
0xA1, 0x01, // Collection (Application),
|
||||
0x75, 0x01, // Report Size (1),
|
||||
0x95, 0x08, // Report Count (8),
|
||||
0x05, 0x07, // Usage Page (Key Codes),
|
||||
0x19, 0xE0, // Usage Minimum (224),
|
||||
0x29, 0xE7, // Usage Maximum (231),
|
||||
0x15, 0x00, // Logical Minimum (0),
|
||||
0x25, 0x01, // Logical Maximum (1),
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute), ; Modifier keys
|
||||
0x95, 0x01, // Report Count (1),
|
||||
0x75, 0x08, // Report Size (8),
|
||||
0x81, 0x03, // Input (Constant), ; Reserved byte
|
||||
0x95, 0x05, // Report Count (5),
|
||||
0x75, 0x01, // Report Size (1),
|
||||
0x05, 0x08, // Usage Page (LEDs),
|
||||
0x19, 0x01, // Usage Minimum (1),
|
||||
0x29, 0x05, // Usage Maximum (5),
|
||||
0x91, 0x02, // Output (Data, Variable, Absolute), ; LED report
|
||||
0x95, 0x01, // Report Count (1),
|
||||
0x75, 0x03, // Report Size (3),
|
||||
0x91, 0x03, // Output (Constant), ; LED report padding
|
||||
0x95, 0x06, // Report Count (6),
|
||||
0x75, 0x08, // Report Size (8),
|
||||
0x15, 0x00, // Logical Minimum (0),
|
||||
0x25, 0x7F, // Logical Maximum(104),
|
||||
0x05, 0x07, // Usage Page (Key Codes),
|
||||
0x19, 0x00, // Usage Minimum (0),
|
||||
0x29, 0x7F, // Usage Maximum (104),
|
||||
0x81, 0x00, // Input (Data, Array), ; Normal keys
|
||||
0xC0, // End Collection
|
||||
}
|
||||
|
||||
var descHIDReportMediaKey = [...]uint8{
|
||||
0x05, 0x0C, // Usage Page (Consumer)
|
||||
0x09, 0x01, // Usage (Consumer Controls)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x75, 0x0A, // Report Size (10)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x19, 0x00, // Usage Minimum (0)
|
||||
0x2A, 0x9C, 0x02, // Usage Maximum (0x29C)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0x9C, 0x02, // Logical Maximum (0x29C)
|
||||
0x81, 0x00, // Input (Data, Array)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x03, // Report Count (3)
|
||||
0x19, 0x00, // Usage Minimum (0)
|
||||
0x29, 0xB7, // Usage Maximum (0xB7)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xB7, 0x00, // Logical Maximum (0xB7)
|
||||
0x81, 0x00, // Input (Data, Array)
|
||||
0xC0, // End Collection
|
||||
}
|
||||
|
||||
var descHIDReportMouse = [...]uint8{
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x02, // Usage (Mouse)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x01, // REPORT_ID (1)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x19, 0x01, // Usage Minimum (Button #1)
|
||||
0x29, 0x08, // Usage Maximum (Button #8)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x95, 0x08, // Report Count (8)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x38, // Usage (Wheel)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8),
|
||||
0x95, 0x03, // Report Count (3),
|
||||
0x81, 0x06, // Input (Data, Variable, Relative)
|
||||
0x05, 0x0C, // Usage Page (Consumer)
|
||||
0x0A, 0x38, 0x02, // Usage (AC Pan)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7F, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8),
|
||||
0x95, 0x01, // Report Count (1),
|
||||
0x81, 0x06, // Input (Data, Variable, Relative)
|
||||
0xC0, // End Collection
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x02, // Usage (Mouse)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x02, // REPORT_ID (2)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
|
||||
0x75, 0x10, // Report Size (16),
|
||||
0x95, 0x02, // Report Count (2),
|
||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||
0xC0, // End Collection
|
||||
}
|
||||
|
||||
var descHIDReportJoystick = [...]uint8{
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x04, // Usage (Joystick)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x20, // Report Count (32)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x19, 0x01, // Usage Minimum (Button #1)
|
||||
0x29, 0x20, // Usage Maximum (Button #32)
|
||||
0x81, 0x02, // Input (variable,absolute)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x07, // Logical Maximum (7)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x46, 0x3B, 0x01, // Physical Maximum (315)
|
||||
0x75, 0x04, // Report Size (4)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x65, 0x14, // Unit (20)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x39, // Usage (Hat switch)
|
||||
0x81, 0x42, // Input (variable,absolute,null_state)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop)
|
||||
0x09, 0x01, // Usage (Pointer)
|
||||
0xA1, 0x00, // Collection ()
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x03, // Logical Maximum (1023)
|
||||
0x75, 0x0A, // Report Size (10)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x32, // Usage (Z)
|
||||
0x09, 0x35, // Usage (Rz)
|
||||
0x81, 0x02, // Input (variable,absolute)
|
||||
0xC0, // End Collection
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x03, // Logical Maximum (1023)
|
||||
0x75, 0x0A, // Report Size (10)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x09, 0x36, // Usage (Slider)
|
||||
0x09, 0x36, // Usage (Slider)
|
||||
0x81, 0x02, // Input (variable,absolute)
|
||||
0xC0, // End Collection
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@ package usb
|
||||
// descCPUFrequencyHz defines the target CPU frequency (Hz).
|
||||
const descCPUFrequencyHz = 600000000
|
||||
|
||||
// descCDCACMCount defines the number of USB cores that may be configured as
|
||||
// CDC-ACM (single) devices.
|
||||
const descCDCACMCount = 0
|
||||
|
||||
// descHIDCount defines the number of USB cores that may be configured as a
|
||||
// composite (keyboard + mouse + joystick) human interface device (HID).
|
||||
const descHIDCount = 1
|
||||
|
||||
// General USB device identification constants.
|
||||
const (
|
||||
descCommonVendorID = 0x16C0
|
||||
@@ -12,39 +20,166 @@ const (
|
||||
descCommonReleaseID = 0x0101 // BCD (1.1)
|
||||
|
||||
descCommonLanguage = descLanguageEnglish
|
||||
descCommonManufacturer = "NXP Semiconductors"
|
||||
descCommonProduct = "TinyGo USB"
|
||||
descCommonSerialNumber = "1"
|
||||
descCommonManufacturer = "TinyGo"
|
||||
descCommonProduct = "USB"
|
||||
descCommonSerialNumber = "00000"
|
||||
)
|
||||
|
||||
// Constants for USB CDC-ACM device classes.
|
||||
const (
|
||||
// descCDCACMCount defines the number of USB cores that will be configured as
|
||||
// CDC-ACM (single) devices.
|
||||
descCDCACMCount = 1
|
||||
descCDCACMMaxPower = 50 // 100 mA
|
||||
|
||||
// CDC-ACM Control Buffers
|
||||
|
||||
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
|
||||
descCDCACMRDCount = 2 * descCDCACMEndpointCount
|
||||
descCDCACMTDCount = descCDCACMEndpointCount
|
||||
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
|
||||
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
|
||||
descCDCACMCxCount = 8
|
||||
|
||||
descCDCACMMaxPower = 50 // 100 mA
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
descCDCACMRDCount = 2 * descCDCACMEndpointCount
|
||||
descCDCACMRxSize = descCDCACMDataRxPacketSize
|
||||
descCDCACMRxCount = descCDCACMRxSize * descCDCACMRDCount
|
||||
|
||||
descCDCACMTDCount = descCDCACMEndpointCount
|
||||
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
|
||||
descCDCACMTxCount = descCDCACMTxSize * descCDCACMTDCount
|
||||
|
||||
descCDCACMTxTimeoutMs = 120 // millisec
|
||||
descCDCACMTxSyncUs = 75 // microsec
|
||||
|
||||
descCDCACMStatusPacketSize = 16
|
||||
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // high-speed
|
||||
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // high-speed
|
||||
descCDCACMRxSize = descCDCACMDataRxPacketSize
|
||||
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
|
||||
// Default CDC-ACM Endpoint Configurations (High-Speed)
|
||||
|
||||
descCDCACMDataRxFSPacketSize = 64 // full-speed
|
||||
descCDCACMDataTxFSPacketSize = 64 // full-speed
|
||||
descCDCACMDataRxHSPacketSize = 512 // high-speed
|
||||
descCDCACMDataTxHSPacketSize = 512 // high-speed
|
||||
descCDCACMStatusInterval = descCDCACMStatusHSInterval // Status
|
||||
descCDCACMStatusPacketSize = descCDCACMStatusHSPacketSize //
|
||||
|
||||
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // Data Rx
|
||||
|
||||
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // Data Tx
|
||||
|
||||
// CDC-ACM Endpoint Configurations for Full-Speed Device
|
||||
|
||||
descCDCACMStatusFSInterval = 5 // Status
|
||||
descCDCACMStatusFSPacketSize = 16 // (full-speed)
|
||||
|
||||
descCDCACMDataRxFSPacketSize = 64 // Data Rx (full-speed)
|
||||
|
||||
descCDCACMDataTxFSPacketSize = 64 // Data Tx (full-speed)
|
||||
|
||||
// CDC-ACM Endpoint Configurations for High-Speed Device
|
||||
|
||||
descCDCACMStatusHSInterval = 5 // Status
|
||||
descCDCACMStatusHSPacketSize = 16 // (high-speed)
|
||||
|
||||
descCDCACMDataRxHSPacketSize = 512 // Data Rx (high-speed)
|
||||
|
||||
descCDCACMDataTxHSPacketSize = 512 // Data Tx (high-speed)
|
||||
)
|
||||
|
||||
// Constants for USB HID (keyboard, mouse, joystick) device classes.
|
||||
const (
|
||||
descHIDMaxPower = 50 // 100 mA
|
||||
|
||||
// HID Control Buffers
|
||||
|
||||
descHIDQHCount = 2 * (descHIDEndpointCount + 1)
|
||||
descHIDCxCount = 8
|
||||
|
||||
// HID Serial Buffers
|
||||
|
||||
descHIDSerialRDCount = 8
|
||||
descHIDSerialRxSize = descHIDSerialRxPacketSize
|
||||
descHIDSerialRxCount = descHIDSerialRxSize * descHIDSerialRDCount
|
||||
|
||||
descHIDSerialTDCount = 12
|
||||
descHIDSerialTxSize = descHIDSerialTxPacketSize
|
||||
descHIDSerialTxCount = descHIDSerialTxSize * descHIDSerialTDCount
|
||||
|
||||
descHIDSerialTxTimeoutMs = 50 // millisec
|
||||
descHIDSerialTxSyncUs = 75 // microsec
|
||||
|
||||
// HID Keyboard Buffers
|
||||
|
||||
descHIDKeyboardTDCount = 12
|
||||
descHIDKeyboardTxSize = 4 * descHIDKeyboardTxPacketSize
|
||||
descHIDKeyboardTxCount = descHIDKeyboardTxSize * descHIDKeyboardTDCount
|
||||
|
||||
descHIDKeyboardTxTimeoutMs = 50 // millisec
|
||||
|
||||
// HID Mouse Buffers
|
||||
|
||||
descHIDMouseTDCount = 4
|
||||
descHIDMouseTxSize = 4 * descHIDMouseTxPacketSize
|
||||
descHIDMouseTxCount = descHIDMouseTxSize * descHIDMouseTDCount
|
||||
|
||||
descHIDMouseTxTimeoutMs = 30 // millisec
|
||||
|
||||
// HID Joystick Buffers
|
||||
|
||||
descHIDJoystickTDCount = 4
|
||||
descHIDJoystickTxSize = 4 * descHIDJoystickTxPacketSize
|
||||
descHIDJoystickTxCount = descHIDJoystickTxSize * descHIDJoystickTDCount
|
||||
|
||||
descHIDJoystickTxTimeoutMs = 30 // millisec
|
||||
|
||||
// Default HID Endpoint Configurations (High-Speed)
|
||||
|
||||
descHIDSerialRxInterval = descHIDSerialRxHSInterval // Serial Rx
|
||||
descHIDSerialRxPacketSize = descHIDSerialRxHSPacketSize //
|
||||
|
||||
descHIDSerialTxInterval = descHIDSerialTxHSInterval // Serial Tx
|
||||
descHIDSerialTxPacketSize = descHIDSerialTxHSPacketSize //
|
||||
|
||||
descHIDKeyboardTxInterval = descHIDKeyboardTxHSInterval // Keyboard
|
||||
descHIDKeyboardTxPacketSize = descHIDKeyboardTxHSPacketSize //
|
||||
|
||||
descHIDMediaKeyTxInterval = descHIDMediaKeyTxHSInterval // Keyboard Media Keys
|
||||
descHIDMediaKeyTxPacketSize = descHIDMediaKeyTxHSPacketSize //
|
||||
|
||||
descHIDMouseTxInterval = descHIDMouseTxHSInterval // Mouse
|
||||
descHIDMouseTxPacketSize = descHIDMouseTxHSPacketSize //
|
||||
|
||||
descHIDJoystickTxInterval = descHIDJoystickTxHSInterval // Joystick
|
||||
descHIDJoystickTxPacketSize = descHIDJoystickTxHSPacketSize //
|
||||
|
||||
// HID Endpoint Configurations for Full-Speed Device
|
||||
|
||||
descHIDSerialRxFSInterval = 2 // Serial Rx
|
||||
descHIDSerialRxFSPacketSize = 8 // (full-speed)
|
||||
|
||||
descHIDSerialTxFSInterval = 1 // Serial Tx
|
||||
descHIDSerialTxFSPacketSize = 16 // (full-speed)
|
||||
|
||||
descHIDKeyboardTxFSInterval = 4 // Keyboard
|
||||
descHIDKeyboardTxFSPacketSize = 8 // (full-speed)
|
||||
|
||||
descHIDMediaKeyTxFSInterval = 4 // Keyboard Media Keys
|
||||
descHIDMediaKeyTxFSPacketSize = 8 // (full-speed)
|
||||
|
||||
descHIDMouseTxFSInterval = 4 // Mouse
|
||||
descHIDMouseTxFSPacketSize = 8 // (full-speed)
|
||||
|
||||
descHIDJoystickTxFSInterval = 4 // Joystick
|
||||
descHIDJoystickTxFSPacketSize = 12 // (full-speed)
|
||||
|
||||
// HID Endpoint Configurations for High-Speed Device
|
||||
|
||||
descHIDSerialRxHSInterval = 2 // Serial
|
||||
descHIDSerialRxHSPacketSize = 32 // (high-speed)
|
||||
|
||||
descHIDSerialTxHSInterval = 1 // Serial Tx
|
||||
descHIDSerialTxHSPacketSize = 64 // (high-speed)
|
||||
|
||||
descHIDKeyboardTxHSInterval = 1 // Keyboard
|
||||
descHIDKeyboardTxHSPacketSize = 8 // (high-speed)
|
||||
|
||||
descHIDMediaKeyTxHSInterval = 4 // Keyboard Media Keys
|
||||
descHIDMediaKeyTxHSPacketSize = 8 // (high-speed)
|
||||
|
||||
descHIDMouseTxHSInterval = 1 // Mouse
|
||||
descHIDMouseTxHSPacketSize = 8 // (high-speed)
|
||||
|
||||
descHIDJoystickTxHSInterval = 2 // Joystick
|
||||
descHIDJoystickTxHSPacketSize = 12 // (high-speed)
|
||||
)
|
||||
|
||||
// descCDCACM0QH is an array of endpoint queue heads, which is where all
|
||||
@@ -71,18 +206,28 @@ const (
|
||||
//go:align 4096
|
||||
var descCDCACM0QH [descCDCACMQHCount]dhwEndpoint
|
||||
|
||||
// descCDCACM0CD is the transfer descriptor for data messages transmitted or
|
||||
// received on the status/control endpoint 0 for the default CDC-ACM (single)
|
||||
// device class configuration (index 1).
|
||||
// descCDCACM0CD is the transfer descriptor for messages transmitted or received
|
||||
// on the status/control endpoint 0 for the default CDC-ACM (single) device
|
||||
// class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0CD dhwTransfer
|
||||
|
||||
// descCDCACM0Cx is the buffer for control/status data received on endpoint 0 of
|
||||
// the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Cx [descCDCACMCxCount]uint8
|
||||
|
||||
// descCDCACM0AD is the transfer descriptor for ackowledgement (ACK) messages
|
||||
// transmitted or received on the status/control endpoint 0 for the default
|
||||
// CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0AD dhwTransfer
|
||||
|
||||
// descCDCACM0Dx is the transmit (Tx) buffer of descriptor data on endpoint 0
|
||||
// for the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Dx [descCDCACMConfigSize]uint8
|
||||
|
||||
// descCDCACM0RD is an array of transfer descriptors for Rx (OUT) transfers,
|
||||
// which describe to the device controller the location and quantity of data
|
||||
// being received for a given transfer, for the default CDC-ACM (single) device
|
||||
@@ -90,6 +235,11 @@ var descCDCACM0AD dhwTransfer
|
||||
//go:align 32
|
||||
var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
|
||||
|
||||
// descCDCACM0Rx is the receive (Rx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Rx [descCDCACMRxCount]uint8
|
||||
|
||||
// descCDCACM0TD is an array of transfer descriptors for Tx (IN) transfers,
|
||||
// which describe to the device controller the location and quantity of data
|
||||
// being transmitted for a given transfer, for the default CDC-ACM (single)
|
||||
@@ -97,36 +247,16 @@ var descCDCACM0RD [descCDCACMRDCount]dhwTransfer
|
||||
//go:align 32
|
||||
var descCDCACM0TD [descCDCACMTDCount]dhwTransfer
|
||||
|
||||
// descCDCACM0LineCoding holds the emulated UART line coding for the default
|
||||
// CDC-ACM (single) device class configuration (index 1).
|
||||
// i.e., configuration index 1.
|
||||
//go:align 32
|
||||
var descCDCACM0LC descCDCACMLineCoding
|
||||
|
||||
// descCDCACM0Cx is the buffer for control/status data received on endpoint 0 of
|
||||
// the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Cx [descCDCACMCxCount]uint8
|
||||
|
||||
// descCDCACM0Rx is the receive (Rx) buffer of data endpoints for the default
|
||||
// CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Rx [descCDCACMRxCount]uint8
|
||||
|
||||
// descCDCACM0Tx is the transmit (Tx) buffer of data endpoints for the default
|
||||
// CDC-ACM (single) device class configuration (index 1).
|
||||
// descCDCACM0Tx is the transmit (Tx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Tx [descCDCACMTxCount]uint8
|
||||
|
||||
// descCDCACM0Dx is the transmit (Tx) buffer of descriptor data for the default
|
||||
// CDC-ACM (single) device class configuration (index 1).
|
||||
var descCDCACM0Dx [descCDCACMConfigSize]uint8
|
||||
|
||||
var descCDCACM0RDNum [descCDCACMRDCount]uint16
|
||||
var descCDCACM0RDIdx [descCDCACMRDCount]uint16
|
||||
var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
|
||||
var descCDCACM0RDQue [(descCDCACMRDCount + 1)]uint16
|
||||
|
||||
// descCDCACM holds the buffers and control states for all of the CDC-ACM
|
||||
// descCDCACMClassData holds the buffers and control states for all CDC-ACM
|
||||
// (single) device class configurations, ordered by index (offset by -1), for
|
||||
// iMXRT1062 targets only.
|
||||
//
|
||||
@@ -134,21 +264,30 @@ var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
|
||||
// of the common/target-agnostic CDC-ACM class configurations (descCDCACM).
|
||||
// Methods defined on this type implement target-specific functionality, and
|
||||
// some of these methods are required by the common device controller driver.
|
||||
// Thus, this type functions as an additional hardware abstraction layer.
|
||||
// Thus, this type functions as a hardware abstraction layer (HAL).
|
||||
type descCDCACMClassData struct {
|
||||
|
||||
// CDC-ACM Control Buffers
|
||||
|
||||
qh *[descCDCACMQHCount]dhwEndpoint // endpoint queue heads
|
||||
|
||||
cd *dhwTransfer // control endpoint 0 Rx/Tx data transfer descriptor
|
||||
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
|
||||
rd *[descCDCACMRDCount]dhwTransfer // bulk data endpoint Rx (OUT) transfer descriptors
|
||||
td *[descCDCACMTDCount]dhwTransfer // bulk data endpoint Tx (IN) transfer descriptors
|
||||
|
||||
cd *dhwTransfer // control endpoint 0 Rx/Tx transfer descriptor
|
||||
cx *[descCDCACMCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
||||
rx *[descCDCACMRxCount]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
||||
tx *[descCDCACMTxCount]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
||||
dx *[descCDCACMConfigSize]uint8 // descriptor data Tx (IN) transfer buffer
|
||||
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
|
||||
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||
|
||||
cxSize uint16
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
rd *[descCDCACMRDCount]dhwTransfer // bulk data endpoint Rx (OUT) transfer descriptors
|
||||
rx *[descCDCACMRxCount]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
||||
td *[descCDCACMTDCount]dhwTransfer // bulk data endpoint Tx (IN) transfer descriptors
|
||||
tx *[descCDCACMTxCount]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
||||
|
||||
rxCount *[descCDCACMRDCount]uint16
|
||||
rxIndex *[descCDCACMRDCount]uint16
|
||||
rxQueue *[(descCDCACMRDCount + 1)]uint16
|
||||
|
||||
sxSize uint16
|
||||
rxSize uint16
|
||||
txSize uint16
|
||||
|
||||
@@ -159,40 +298,307 @@ type descCDCACMClassData struct {
|
||||
rxHead uint8
|
||||
rxTail uint8
|
||||
rxFree uint16
|
||||
|
||||
rxCount *[descCDCACMRDCount]uint16
|
||||
rxIndex *[descCDCACMRDCount]uint16
|
||||
rxQueue *[descCDCACMRDCount + 1]uint16
|
||||
|
||||
_ [2]uint8
|
||||
}
|
||||
|
||||
// descCDCACMData holds statically-allocated instances for each of the target-
|
||||
// specific (iMXRT1062) CDC-ACM (single) device class configurations' control
|
||||
// and data structures, ordered by configuration index (offset by -1). Each
|
||||
// element is embedded in a corresponding element of descCDCACM.
|
||||
//go:align 32
|
||||
var descCDCACMData = [descCDCACMCount]descCDCACMClassData{
|
||||
//go:align 64
|
||||
var descCDCACMData = [dcdCount]descCDCACMClassData{
|
||||
|
||||
{ // -- CDC-ACM (single) Class Configuration Index 1 --
|
||||
|
||||
// CDC-ACM Control Buffers
|
||||
|
||||
{ // CDC-ACM (single) class configuration index 1 data
|
||||
qh: &descCDCACM0QH,
|
||||
|
||||
cd: &descCDCACM0CD,
|
||||
ad: &descCDCACM0AD,
|
||||
rd: &descCDCACM0RD,
|
||||
td: &descCDCACM0TD,
|
||||
|
||||
cx: &descCDCACM0Cx,
|
||||
rx: &descCDCACM0Rx,
|
||||
tx: &descCDCACM0Tx,
|
||||
ad: &descCDCACM0AD,
|
||||
dx: &descCDCACM0Dx,
|
||||
|
||||
cxSize: descCDCACMStatusPacketSize,
|
||||
rxSize: descCDCACMDataRxPacketSize,
|
||||
txSize: descCDCACMDataTxPacketSize,
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
rd: &descCDCACM0RD,
|
||||
rx: &descCDCACM0Rx,
|
||||
td: &descCDCACM0TD,
|
||||
tx: &descCDCACM0Tx,
|
||||
|
||||
rxCount: &descCDCACM0RDNum,
|
||||
rxIndex: &descCDCACM0RDIdx,
|
||||
rxQueue: &descCDCACM0RDQue,
|
||||
|
||||
sxSize: descCDCACMStatusPacketSize,
|
||||
rxSize: descCDCACMDataRxPacketSize,
|
||||
txSize: descCDCACMDataTxPacketSize,
|
||||
},
|
||||
}
|
||||
|
||||
// descHID0QH is an array of endpoint queue heads, which is where all transfers
|
||||
// for a given endpoint are managed, for the default HID device class
|
||||
// configuration (index 1).
|
||||
//
|
||||
// From the iMXRT1062 Reference Manual:
|
||||
//
|
||||
// Software must ensure that no interface data structure reachable
|
||||
// by the Device Controller spans a 4K-page boundary.
|
||||
//
|
||||
// The [queue head] is a 48-byte data structure, but must be aligned on
|
||||
// 64-byte boundaries.
|
||||
//
|
||||
// Endpoint queue heads are arranged in an array in a continuous area of
|
||||
// memory pointed to by the USB.ENDPOINTLISTADDR pointer. The even-numbered
|
||||
// device queue heads in the list support receive endpoints (OUT/SETUP) and
|
||||
// the odd-numbered queue heads in the list are used for transmit endpoints
|
||||
// (IN/INTERRUPT). The device controller will index into this array based upon
|
||||
// the endpoint number received from the USB bus. All information necessary to
|
||||
// respond to transactions for all primed transfers is contained in this list
|
||||
// so the Device Controller can readily respond to incoming requests without
|
||||
// having to traverse a linked list.
|
||||
//go:align 4096
|
||||
var descHID0QH [descHIDQHCount]dhwEndpoint
|
||||
|
||||
// descHID0CD is the transfer descriptor for messages transmitted or received on
|
||||
// the status/control endpoint 0 for the default HID device class configuration
|
||||
// (index 1).
|
||||
//go:align 32
|
||||
var descHID0CD dhwTransfer
|
||||
|
||||
// descHID0Cx is the buffer for control/status data received on endpoint 0 of
|
||||
// the default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0Cx [descHIDCxCount]uint8
|
||||
|
||||
// descHID0AD is the transfer descriptor for ackowledgement (ACK) messages
|
||||
// transmitted or received on the status/control endpoint 0 for the default HID
|
||||
// device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0AD dhwTransfer
|
||||
|
||||
// descHID0Dx is the transmit (Tx) buffer of descriptor data on endpoint 0 for
|
||||
// the default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0Dx [descHIDConfigSize]uint8
|
||||
|
||||
// descHID0SerialRD is an array of transfer descriptors for serial Rx (OUT)
|
||||
// transfers, which describe to the device controller the location and quantity
|
||||
// of data being received for a given transfer, for the default HID device class
|
||||
// configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0SerialRD [descHIDSerialRDCount]dhwTransfer
|
||||
|
||||
// descHID0SerialRx is the serial receive (Rx) transfer buffer for the default
|
||||
// HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0SerialRx [descHIDSerialRxCount]uint8
|
||||
|
||||
// descHID0SerialTD is an array of transfer descriptors for serial Tx (IN)
|
||||
// transfers, which describe to the device controller the location and quantity
|
||||
// of data being transmitted for a given transfer, for the default HID device
|
||||
// class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0SerialTD [descHIDSerialTDCount]dhwTransfer
|
||||
|
||||
// descHID0SerialTx is the serial transmit (Tx) transfer buffer for the default
|
||||
// HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0SerialTx [descHIDSerialTxCount]uint8
|
||||
|
||||
var descHID0SerialRDIdx [descHIDSerialRDCount]uint16
|
||||
var descHID0SerialRDQue [(descHIDSerialRDCount + 1)]uint16
|
||||
|
||||
// descHID0KeyboardTD is an array of transfer descriptors for keyboard Tx (IN)
|
||||
// transfers, which describe to the device controller the location and quantity
|
||||
// of data being transmitted for a given transfer, for the default HID device
|
||||
// class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0KeyboardTD [descHIDKeyboardTDCount]dhwTransfer
|
||||
|
||||
// descHID0KeyboardTx is the keyboard transmit (Tx) transfer buffer for the
|
||||
// default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0KeyboardTx [descHIDKeyboardTxCount]uint8
|
||||
|
||||
// descHID0KeyboardTp is the keyboard HID report transmit (Tx) transfer buffer
|
||||
// for the default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0KeyboardTp [descHIDKeyboardTxPacketSize]uint8
|
||||
|
||||
//go:align 32
|
||||
var descHID0KeyboardTxKey [hidKeyboardKeyCount]uint8
|
||||
|
||||
//go:align 32
|
||||
var descHID0KeyboardTxCon [hidKeyboardConCount]uint16
|
||||
|
||||
//go:align 32
|
||||
var descHID0KeyboardTxSys [hidKeyboardSysCount]uint8
|
||||
|
||||
// descHID0MouseTD is an array of transfer descriptors for mouse Tx (IN)
|
||||
// transfers, which describe to the device controller the location and quantity
|
||||
// of data being transmitted for a given transfer, for the default HID device
|
||||
// class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0MouseTD [descHIDMouseTDCount]dhwTransfer
|
||||
|
||||
// descHID0MouseTx is the mouse transmit (Tx) transfer buffer for the default
|
||||
// HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0MouseTx [descHIDMouseTxCount]uint8
|
||||
|
||||
// descHID0JoystickTD is an array of transfer descriptors for joystick Tx (IN)
|
||||
// transfers, which describe to the device controller the location and quantity
|
||||
// of data being transmitted for a given transfer, for the default HID device
|
||||
// class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0JoystickTD [descHIDJoystickTDCount]dhwTransfer
|
||||
|
||||
// descHID0JoystickTx is the joystick transmit (Tx) transfer buffer for the
|
||||
// default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0JoystickTx [descHIDJoystickTxCount]uint8
|
||||
|
||||
// descHID0Keyboard is the Keyboard instance with which the user may interact
|
||||
// when using the default HID device class configuration (index 1).
|
||||
//go:align 64
|
||||
var descHID0Keyboard = Keyboard{
|
||||
key: &descHID0KeyboardTxKey,
|
||||
con: &descHID0KeyboardTxCon,
|
||||
sys: &descHID0KeyboardTxSys,
|
||||
}
|
||||
|
||||
// descHIDClassData holds the buffers and control states for all of the HID
|
||||
// device class configurations, ordered by index (offset by -1), for iMXRT1062
|
||||
// targets only.
|
||||
//
|
||||
// Instances of this type (elements of descHIDData) are embedded in elements
|
||||
// of the common/target-agnostic HID class configurations (descHID).
|
||||
// Methods defined on this type implement target-specific functionality, and
|
||||
// some of these methods are required by the common device controller driver.
|
||||
// Thus, this type functions as a hardware abstraction layer (HAL).
|
||||
type descHIDClassData struct {
|
||||
|
||||
// HID Control Buffers
|
||||
|
||||
qh *[descHIDQHCount]dhwEndpoint // endpoint queue heads
|
||||
|
||||
cd *dhwTransfer // control endpoint 0 Rx/Tx transfer descriptor
|
||||
cx *[descHIDCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
||||
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
|
||||
dx *[descHIDConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||
|
||||
// HID Serial Buffers
|
||||
|
||||
rdSerial *[descHIDSerialRDCount]dhwTransfer // interrupt endpoint serial Rx (OUT) transfer descriptors
|
||||
rxSerial *[descHIDSerialRxCount]uint8 // interrupt endpoint serial Rx (OUT) transfer buffer
|
||||
tdSerial *[descHIDSerialTDCount]dhwTransfer // interrupt endpoint serial Tx (IN) transfer descriptors
|
||||
txSerial *[descHIDSerialTxCount]uint8 // interrupt endpoint serial Tx (IN) transfer buffer
|
||||
|
||||
rxSerialIndex *[descHIDSerialRDCount]uint16
|
||||
rxSerialQueue *[(descHIDSerialRDCount + 1)]uint16
|
||||
|
||||
rxSerialSize uint16
|
||||
txSerialSize uint16
|
||||
|
||||
txSerialHead uint8
|
||||
txSerialFree uint16
|
||||
txSerialPrev bool
|
||||
|
||||
rxSerialHead uint8
|
||||
rxSerialTail uint8
|
||||
rxSerialFree uint16
|
||||
|
||||
// HID Keyboard Buffers
|
||||
|
||||
tdKeyboard *[descHIDKeyboardTDCount]dhwTransfer // interrupt endpoint keyboard Tx (IN) transfer descriptors
|
||||
txKeyboard *[descHIDKeyboardTxCount]uint8 // interrupt endpoint keyboard Tx (IN) transfer buffer
|
||||
tpKeyboard *[descHIDKeyboardTxPacketSize]uint8 // interrupt endpoint keyboard Tx (IN) HID report bbuffer
|
||||
|
||||
txKeyboardSize uint16
|
||||
|
||||
txKeyboardHead uint8
|
||||
txKeyboardPrev bool
|
||||
|
||||
// HID Mouse Buffers
|
||||
|
||||
tdMouse *[descHIDMouseTDCount]dhwTransfer // interrupt endpoint mouse Tx (IN) transfer descriptors
|
||||
txMouse *[descHIDMouseTxCount]uint8 // interrupt endpoint mouse Tx (IN) transfer buffer
|
||||
|
||||
txMouseSize uint16
|
||||
|
||||
txMouseHead uint8
|
||||
txMousePrev bool
|
||||
|
||||
// HID Joystick Buffers
|
||||
|
||||
tdJoystick *[descHIDJoystickTDCount]dhwTransfer // interrupt endpoint joystick Tx (IN) transfer descriptors
|
||||
txJoystick *[descHIDJoystickTxCount]uint8 // interrupt endpoint joystick Tx (IN) transfer buffer
|
||||
|
||||
txJoystickSize uint16
|
||||
|
||||
txJoystickHead uint8
|
||||
txJoystickPrev bool
|
||||
|
||||
// HID Device Instances
|
||||
|
||||
keyboard *Keyboard
|
||||
}
|
||||
|
||||
// descHIDData holds statically-allocated instances for each of the target-
|
||||
// specific (iMXRT1062) HID device class configurations' control and data
|
||||
// structures, ordered by configuration index (offset by -1). Each element is
|
||||
// embedded in a corresponding element of descHID.
|
||||
//go:align 64
|
||||
var descHIDData = [dcdCount]descHIDClassData{
|
||||
|
||||
{ // -- HID Class Configuration Index 1 --
|
||||
|
||||
// HID Control Buffers
|
||||
|
||||
qh: &descHID0QH,
|
||||
|
||||
cd: &descHID0CD,
|
||||
cx: &descHID0Cx,
|
||||
ad: &descHID0AD,
|
||||
dx: &descHID0Dx,
|
||||
|
||||
// HID Serial Buffers
|
||||
|
||||
rdSerial: &descHID0SerialRD,
|
||||
rxSerial: &descHID0SerialRx,
|
||||
tdSerial: &descHID0SerialTD,
|
||||
txSerial: &descHID0SerialTx,
|
||||
|
||||
rxSerialIndex: &descHID0SerialRDIdx,
|
||||
rxSerialQueue: &descHID0SerialRDQue,
|
||||
|
||||
rxSerialSize: descHIDSerialRxPacketSize,
|
||||
txSerialSize: descHIDSerialTxPacketSize,
|
||||
|
||||
// HID Keyboard Buffers
|
||||
|
||||
tdKeyboard: &descHID0KeyboardTD,
|
||||
txKeyboard: &descHID0KeyboardTx,
|
||||
tpKeyboard: &descHID0KeyboardTp,
|
||||
|
||||
txKeyboardSize: descHIDKeyboardTxPacketSize,
|
||||
|
||||
// HID Mouse Buffers
|
||||
|
||||
tdMouse: &descHID0MouseTD,
|
||||
txMouse: &descHID0MouseTx,
|
||||
|
||||
txMouseSize: descHIDMouseTxPacketSize,
|
||||
|
||||
// HID Joystick Buffers
|
||||
|
||||
tdJoystick: &descHID0JoystickTD,
|
||||
txJoystick: &descHID0JoystickTx,
|
||||
|
||||
txJoystickSize: descHIDJoystickTxPacketSize,
|
||||
|
||||
// HID Device Instances
|
||||
|
||||
keyboard: &descHID0Keyboard,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ type dhw struct {
|
||||
sofUsage uint8
|
||||
}
|
||||
|
||||
func runBootloader() { arm.Asm(`bkpt #251`) }
|
||||
|
||||
// cycleCount uses the ARM debug cycle counter available on iMXRT1062 (enabled
|
||||
// in runtime_mimxrt1062_time.go) to return the number of CPU cycles since boot.
|
||||
//go:inline
|
||||
@@ -184,7 +186,9 @@ func (d *dhw) enableSOF(enable bool, iface uint8) {
|
||||
d.bus.USBINTR.SetBits(nxp.USB_USBINTR_SRE)
|
||||
}
|
||||
arm.EnableInterrupts(ivm)
|
||||
d.timerReboot = 80
|
||||
} else {
|
||||
d.timerReboot = 0
|
||||
d.sofUsage &^= 1 << iface
|
||||
if 0 == d.sofUsage {
|
||||
d.bus.USBINTR.ClearBits(nxp.USB_USBINTR_SRE)
|
||||
@@ -354,33 +358,23 @@ func (d *dhw) interrupt() {
|
||||
d.timerReboot -= 1
|
||||
if 0 == d.timerReboot {
|
||||
d.enableSOF(false, descCDCACMInterfaceCount)
|
||||
runBootloader()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) controlBusSpeed() uint8 { return d.busSpeed }
|
||||
func (d *dhw) speed() uint8 { return d.busSpeed }
|
||||
|
||||
func (d *dhw) controlDeviceAddress(addr uint16) {
|
||||
func (d *dhw) setDeviceAddress(addr uint16) {
|
||||
d.bus.DEVICEADDR.Set(nxp.USB_DEVICEADDR_USBADRA |
|
||||
((uint32(addr) << nxp.USB_DEVICEADDR_USBADR_Pos) &
|
||||
nxp.USB_DEVICEADDR_USBADR_Msk))
|
||||
}
|
||||
|
||||
func (d *dhw) controlLineState(coding descCDCACMLineCoding, dtr, rts bool) {
|
||||
// TBD: does the PHY need to handle on iMXRT1062 (e.g., Teensyduino Loader)?
|
||||
}
|
||||
|
||||
func (d *dhw) controlLineCoding(coding descCDCACMLineCoding) {
|
||||
if 134 == coding.baud {
|
||||
d.enableSOF(true, descCDCACMInterfaceCount)
|
||||
}
|
||||
}
|
||||
|
||||
// controlStatus transitions transfers on control endpoint 0 into status stage.
|
||||
func (d *dhw) controlStatus() {
|
||||
// Not used on iMXRT1062
|
||||
}
|
||||
// =============================================================================
|
||||
// Control Endpoint 0
|
||||
// =============================================================================
|
||||
|
||||
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
|
||||
// any other endpoint, use method endpointStall().
|
||||
@@ -411,7 +405,7 @@ func (d *dhw) controlReceive(
|
||||
} // wait for endpoint finish priming
|
||||
}
|
||||
ad.next = dhwTransferEOL
|
||||
ad.token = 1 << 7
|
||||
ad.token = 1 << 7 // Bit 7: active transfer
|
||||
if notify {
|
||||
ad.token |= 1 << 15
|
||||
}
|
||||
@@ -424,6 +418,8 @@ func (d *dhw) controlReceive(
|
||||
if notify {
|
||||
d.controlMask = tm
|
||||
}
|
||||
for 0 != d.bus.ENDPTPRIME.Get() {
|
||||
} // wait for endpoint finish priming
|
||||
}
|
||||
|
||||
// controlTransmit transmits (Tx, IN) data on control endpoint 0.
|
||||
@@ -449,7 +445,7 @@ func (d *dhw) controlTransmit(
|
||||
} // wait for endpoint finish priming
|
||||
}
|
||||
ad.next = dhwTransferEOL
|
||||
ad.token = 1 << 7
|
||||
ad.token = 1 << 7 // Bit 7: active transfer
|
||||
if notify {
|
||||
ad.token |= 1 << 15
|
||||
}
|
||||
@@ -462,11 +458,13 @@ func (d *dhw) controlTransmit(
|
||||
if notify {
|
||||
d.controlMask = rm
|
||||
}
|
||||
for 0 != d.bus.ENDPTPRIME.Get() {
|
||||
} // wait for endpoint finish priming
|
||||
}
|
||||
|
||||
// dhwEndpointSize defines the size (bytes) of a structure containing a USB
|
||||
// standard endpoint.
|
||||
const dhwEndpointSize = 64 // bytes
|
||||
// =============================================================================
|
||||
// Endpoint Descriptor
|
||||
// =============================================================================
|
||||
|
||||
// dhwEndpoint defines a USB standard endpoint, used as the general channel of
|
||||
// communication between host and device.
|
||||
@@ -488,6 +486,10 @@ type dhwEndpoint struct {
|
||||
callback func(transfer *dhwTransfer)
|
||||
}
|
||||
|
||||
// dhwEndpointSize defines the size (bytes) of a structure containing a USB
|
||||
// standard endpoint.
|
||||
const dhwEndpointSize = 64 // bytes
|
||||
|
||||
// endpointQueueHead returns the queue head for the given endpoint address,
|
||||
// encoded as direction D and endpoint number N with the 8-bit mask DxxxNNNN.
|
||||
//go:inline
|
||||
@@ -496,6 +498,8 @@ func (d *dhw) endpointQueueHead(endpoint uint8) *dhwEndpoint {
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return &descCDCACM[d.cc.config-1].qh[endpointIndex(endpoint)]
|
||||
case classDeviceHID:
|
||||
return &descHID[d.cc.config-1].qh[endpointIndex(endpoint)]
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -552,17 +556,23 @@ func (d *dhw) endpointStall(endpoint uint8) {
|
||||
)
|
||||
}
|
||||
|
||||
// func (d *dhw) endpointPrime(mask uint32, transfer *dhwTransfer) {
|
||||
// d.bus.ENDPTPRIME.Set(mask)
|
||||
// }
|
||||
func (d *dhw) endpointClearFeature(endpoint uint8) {
|
||||
switch endpoint {
|
||||
case rxEndpoint(endpoint):
|
||||
d.endpointControlRegister(endpoint).ClearBits(nxp.USB_ENDPTCTRL0_RXS)
|
||||
case txEndpoint(endpoint):
|
||||
d.endpointControlRegister(endpoint).ClearBits(nxp.USB_ENDPTCTRL0_TXS)
|
||||
}
|
||||
}
|
||||
|
||||
// func (d *dhw) endpointPrimed() uint32 {
|
||||
// return d.bus.ENDPTPRIME.Get()
|
||||
// }
|
||||
|
||||
// func (d *dhw) endpointUnprime(mask uint32) {
|
||||
// d.bus.ENDPTCOMPLETE.Set(mask)
|
||||
// }
|
||||
func (d *dhw) endpointSetFeature(endpoint uint8) {
|
||||
switch endpoint {
|
||||
case rxEndpoint(endpoint):
|
||||
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_RXS)
|
||||
case txEndpoint(endpoint):
|
||||
d.endpointControlRegister(endpoint).SetBits(nxp.USB_ENDPTCTRL0_TXS)
|
||||
}
|
||||
}
|
||||
|
||||
// endpointConfigure configures the given bulk data endpoint for transfer.
|
||||
func (d *dhw) endpointConfigure(
|
||||
@@ -603,8 +613,8 @@ func (d *dhw) endpointComplete(endpoint uint8) {
|
||||
ep.first = nil
|
||||
ep.last = nil
|
||||
} else {
|
||||
if 0 != t.token&(1<<7) {
|
||||
// active transfer, new list begins here
|
||||
if 0 != t.token&(1<<7) { // Bit 7: active transfer
|
||||
// new list begins here
|
||||
ep.first = t
|
||||
break
|
||||
} else {
|
||||
@@ -634,15 +644,23 @@ func (d *dhw) endpointConfigureRx(
|
||||
endpoint > descCDCACMEndpointCount {
|
||||
return
|
||||
}
|
||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
||||
if nil != callback {
|
||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if endpoint < descHIDEndpointSerialRx ||
|
||||
endpoint > descHIDEndpointCount {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
||||
if nil != callback {
|
||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
||||
}
|
||||
}
|
||||
|
||||
// endpointConfigureTx configures the given bulk data transmit (Tx, IN) endpoint
|
||||
@@ -659,15 +677,23 @@ func (d *dhw) endpointConfigureTx(
|
||||
endpoint > descCDCACMEndpointCount {
|
||||
return
|
||||
}
|
||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
||||
if nil != callback {
|
||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if endpoint < descHIDEndpointSerialRx ||
|
||||
endpoint > descHIDEndpointCount {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
||||
d.endpointConfigure(ep, packetSize, zlp, callback)
|
||||
if nil != callback {
|
||||
d.endpointMask |= (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
||||
}
|
||||
}
|
||||
|
||||
// endpointReceive schedules a receive (Rx, OUT) transfer on the given endpoint.
|
||||
@@ -682,13 +708,21 @@ func (d *dhw) endpointReceive(endpoint uint8, transfer *dhwTransfer) {
|
||||
endpoint > descCDCACMEndpointCount {
|
||||
return
|
||||
}
|
||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
||||
em := (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
||||
d.transferSchedule(ep, em, transfer)
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if endpoint < descHIDEndpointSerialRx ||
|
||||
endpoint > descHIDEndpointCount {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
ep := d.endpointQueueHead(rxEndpoint(endpoint))
|
||||
em := (uint32(1) << endpoint) << descEndptConfigAttrRxPos
|
||||
d.transferSchedule(ep, em, transfer)
|
||||
}
|
||||
|
||||
// endpointTransmit schedules a transmit (Tx, IN) transfer on the given
|
||||
@@ -704,17 +738,26 @@ func (d *dhw) endpointTransmit(endpoint uint8, transfer *dhwTransfer) {
|
||||
endpoint > descCDCACMEndpointCount {
|
||||
return
|
||||
}
|
||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
||||
em := (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
||||
d.transferSchedule(ep, em, transfer)
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if endpoint < descHIDEndpointSerialRx ||
|
||||
endpoint > descHIDEndpointCount {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
ep := d.endpointQueueHead(txEndpoint(endpoint))
|
||||
em := (uint32(1) << endpoint) << descEndptConfigAttrTxPos
|
||||
d.transferSchedule(ep, em, transfer)
|
||||
}
|
||||
|
||||
// dhwTransferSize defines the size (bytes) of a USB standard transfer packet.
|
||||
const dhwTransferSize = 32 // bytes
|
||||
// =============================================================================
|
||||
// Transfer Descriptor
|
||||
// =============================================================================
|
||||
|
||||
// dhwTransfer describes the size and location of data to be transferred to or
|
||||
// from a USB endpoint.
|
||||
@@ -725,6 +768,9 @@ type dhwTransfer struct {
|
||||
param uint32
|
||||
}
|
||||
|
||||
// dhwTransferSize defines the size (bytes) of a USB standard transfer packet.
|
||||
const dhwTransferSize = 32 // bytes
|
||||
|
||||
// dhwTransferEOL is a sentinel value used to indicate the final node in a
|
||||
// linked list of transfer descriptors.
|
||||
var dhwTransferEOL = (*dhwTransfer)(unsafe.Pointer(uintptr(1)))
|
||||
@@ -744,6 +790,8 @@ func (d *dhw) transferControl() (dat, ack *dhwTransfer) {
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return descCDCACM[d.cc.config-1].cd, descCDCACM[d.cc.config-1].ad
|
||||
case classDeviceHID:
|
||||
return descHID[d.cc.config-1].cd, descHID[d.cc.config-1].ad
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
@@ -753,7 +801,9 @@ func (d *dhw) transferPrepare(
|
||||
transfer *dhwTransfer, data *uint8, size uint16, param uint32) {
|
||||
|
||||
transfer.next = dhwTransferEOL
|
||||
transfer.token = (uint32(size) << 16) | (1 << 7)
|
||||
|
||||
// Set 15-bit packet size and transfer active bit 7.
|
||||
transfer.token = (uint32(size&0x7FFF) << 16) | (1 << 7)
|
||||
addr := uintptr(unsafe.Pointer(data))
|
||||
for i := range transfer.pointer {
|
||||
transfer.pointer[i] = addr + uintptr(i)*4096
|
||||
@@ -794,6 +844,10 @@ endTransfer:
|
||||
arm.EnableInterrupts(ivm)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// General-Purpose (GP) Timer
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) timerConfigure(timer int, usec uint32, fn func()) {
|
||||
if timer < 0 || timer >= len(d.timerInterrupt) {
|
||||
return
|
||||
@@ -831,9 +885,15 @@ func (d *dhw) timerStop(timer int) {
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [CDC-ACM] Serial UART (Virtual COM Port)
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) uartConfigure() {
|
||||
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
switch d.controlBusSpeed() {
|
||||
|
||||
switch d.speed() {
|
||||
case descDeviceSpeedHigh:
|
||||
acm.rxSize = descCDCACMDataRxHSPacketSize
|
||||
acm.txSize = descCDCACMDataTxHSPacketSize
|
||||
@@ -843,6 +903,7 @@ func (d *dhw) uartConfigure() {
|
||||
}
|
||||
acm.txHead = 0
|
||||
acm.txFree = 0
|
||||
acm.txPrev = false
|
||||
acm.rxHead = 0
|
||||
acm.rxTail = 0
|
||||
acm.rxFree = 0
|
||||
@@ -855,7 +916,7 @@ func (d *dhw) uartConfigure() {
|
||||
false, descCDCACMConfigAttrDataTx)
|
||||
|
||||
d.endpointConfigureTx(descCDCACMEndpointStatus,
|
||||
acm.cxSize, false, nil)
|
||||
acm.sxSize, false, nil)
|
||||
d.endpointConfigureRx(descCDCACMEndpointDataRx,
|
||||
acm.rxSize, false, d.uartNotify)
|
||||
d.endpointConfigureTx(descCDCACMEndpointDataTx,
|
||||
@@ -866,6 +927,16 @@ func (d *dhw) uartConfigure() {
|
||||
d.timerConfigure(0, descCDCACMTxSyncUs, d.uartSync)
|
||||
}
|
||||
|
||||
func (d *dhw) uartSetLineState(dtr, rts bool) {
|
||||
// TBD: does the PHY need to handle on iMXRT1062 (e.g., Teensyduino Loader)?
|
||||
}
|
||||
|
||||
func (d *dhw) uartSetLineCoding(coding descCDCACMLineCoding) {
|
||||
if 134 == coding.baud {
|
||||
d.enableSOF(true, descCDCACMInterfaceCount)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) uartReceive(endpoint uint8) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||
@@ -1071,3 +1142,263 @@ func (d *dhw) uartSync() {
|
||||
}
|
||||
acm.txFree = 0
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [HID] Serial
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) serialConfigure() {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
switch d.speed() {
|
||||
case descDeviceSpeedHigh:
|
||||
hid.rxSerialSize = descHIDSerialRxHSPacketSize
|
||||
hid.txSerialSize = descHIDSerialTxHSPacketSize
|
||||
default:
|
||||
hid.rxSerialSize = descHIDSerialRxFSPacketSize
|
||||
hid.txSerialSize = descHIDSerialTxFSPacketSize
|
||||
}
|
||||
|
||||
// Rx and Tx are on same endpoint
|
||||
d.endpointEnable(descHIDEndpointSerialRx,
|
||||
false, descHIDConfigAttrSerial)
|
||||
|
||||
d.endpointConfigureRx(descHIDEndpointSerialRx,
|
||||
hid.rxSerialSize, false, d.serialNotify)
|
||||
d.endpointConfigureTx(descHIDEndpointSerialTx,
|
||||
hid.txSerialSize, false, nil)
|
||||
for i := range hid.rdSerial {
|
||||
d.serialReceive(uint8(i))
|
||||
}
|
||||
d.timerConfigure(0, descHIDSerialTxSyncUs, d.serialSync)
|
||||
}
|
||||
|
||||
func (d *dhw) serialReceive(endpoint uint8) {
|
||||
hid := &descHID[d.cc.config-1]
|
||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||
buf := &hid.rxSerial[num*descHIDSerialRxSize]
|
||||
d.enableInterrupts(false)
|
||||
d.transferPrepare(&hid.rdSerial[num], buf, hid.rxSerialSize, uint32(endpoint))
|
||||
deleteCache(uintptr(unsafe.Pointer(buf)), uintptr(hid.rxSerialSize))
|
||||
d.endpointReceive(descHIDEndpointSerialRx, &hid.rdSerial[num])
|
||||
d.enableInterrupts(true)
|
||||
}
|
||||
|
||||
func (d *dhw) serialTransmit() {
|
||||
hid := &descHID[d.cc.config-1]
|
||||
xfer := &hid.tdSerial[hid.txSerialHead]
|
||||
buff := &hid.txSerial[uint16(hid.txSerialHead)*descHIDSerialTxSize]
|
||||
d.transferPrepare(xfer, buff, hid.txSerialSize, 0)
|
||||
flushCache(uintptr(unsafe.Pointer(buff)), uintptr(hid.txSerialSize))
|
||||
d.endpointTransmit(descHIDEndpointSerialTx, xfer)
|
||||
hid.txSerialHead += 1
|
||||
if hid.txSerialHead >= descHIDSerialTDCount {
|
||||
hid.txSerialHead = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) serialNotify(transfer *dhwTransfer) {
|
||||
hid := &descHID[d.cc.config-1]
|
||||
len := hid.rxSerialSize - (uint16(transfer.token>>16) & 0x7FFF)
|
||||
p := transfer.param
|
||||
if len == hid.rxSerialSize && 0 != hid.rxSerial[p*uint32(hid.rxSerialSize)] {
|
||||
// data packet
|
||||
hid.rxSerialIndex[p] = 0
|
||||
h := hid.rxSerialHead + 1
|
||||
if h > descHIDSerialRDCount { // should be >=
|
||||
h = 0
|
||||
}
|
||||
hid.rxSerialQueue[h] = uint16(p)
|
||||
hid.rxSerialHead = h
|
||||
hid.rxSerialFree += len
|
||||
} else {
|
||||
// short packet
|
||||
d.serialReceive(uint8(p))
|
||||
}
|
||||
}
|
||||
|
||||
// serialFlush discards all buffered input (Rx) data.
|
||||
func (d *dhw) serialFlush() {
|
||||
hid := &descHID[d.cc.config-1]
|
||||
tail := hid.rxSerialTail
|
||||
for tail != hid.rxSerialHead {
|
||||
tail += 1
|
||||
if tail > descHIDSerialRDCount {
|
||||
tail = 0
|
||||
}
|
||||
i := hid.rxSerialQueue[tail]
|
||||
d.serialReceive(uint8(i))
|
||||
hid.rxSerialTail = tail
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) serialSync() {
|
||||
const autoFlushTx = true
|
||||
if !autoFlushTx {
|
||||
return
|
||||
}
|
||||
hid := &descHID[d.cc.config-1]
|
||||
if 0 == hid.txSerialFree {
|
||||
return
|
||||
}
|
||||
xfer := &hid.tdSerial[hid.txSerialHead]
|
||||
buff := &hid.txSerial[uint16(hid.txSerialHead)*descHIDSerialTxSize]
|
||||
size := descHIDSerialTxSize - hid.txSerialFree
|
||||
d.transferPrepare(xfer, buff, size, 0)
|
||||
flushCache(uintptr(unsafe.Pointer(buff)), uintptr(size))
|
||||
d.endpointTransmit(descHIDEndpointSerialTx, xfer)
|
||||
hid.txSerialHead += 1
|
||||
if hid.txSerialHead >= descHIDSerialTDCount {
|
||||
hid.txSerialHead = 0
|
||||
}
|
||||
hid.txSerialFree = 0
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [HID] Keyboard
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) keyboard() *Keyboard { return descHID[d.cc.config-1].keyboard }
|
||||
|
||||
func (d *dhw) keyboardConfigure() {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
// Initialize keyboard
|
||||
hid.keyboard.configure(d.dcd, hid)
|
||||
|
||||
switch d.speed() {
|
||||
case descDeviceSpeedHigh:
|
||||
hid.txKeyboardSize = descHIDKeyboardTxHSPacketSize
|
||||
default:
|
||||
hid.txKeyboardSize = descHIDKeyboardTxFSPacketSize
|
||||
}
|
||||
|
||||
d.endpointEnable(descHIDEndpointKeyboard,
|
||||
false, descHIDConfigAttrKeyboard)
|
||||
d.endpointEnable(descHIDEndpointMediaKey,
|
||||
false, descHIDConfigAttrMediaKey)
|
||||
|
||||
d.endpointConfigureTx(descHIDEndpointKeyboard,
|
||||
hid.txKeyboardSize, false, nil)
|
||||
d.endpointConfigureTx(descHIDEndpointMediaKey,
|
||||
hid.txKeyboardSize, false, nil)
|
||||
}
|
||||
|
||||
func (d *dhw) keyboardSendKeys(consumer bool) bool {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
if !consumer {
|
||||
|
||||
hid.tpKeyboard[0] = hid.keyboard.mod
|
||||
hid.tpKeyboard[1] = 0
|
||||
hid.tpKeyboard[2] = hid.keyboard.key[0]
|
||||
hid.tpKeyboard[3] = hid.keyboard.key[1]
|
||||
hid.tpKeyboard[4] = hid.keyboard.key[2]
|
||||
hid.tpKeyboard[5] = hid.keyboard.key[3]
|
||||
hid.tpKeyboard[6] = hid.keyboard.key[4]
|
||||
hid.tpKeyboard[7] = hid.keyboard.key[5]
|
||||
|
||||
return d.keyboardWrite(descHIDEndpointKeyboard, hid.tpKeyboard[:])
|
||||
|
||||
} else {
|
||||
|
||||
// 44444444 44333333 33332222 22222211 11111111 [ word ]
|
||||
// 98765432 10987654 32109876 54321098 76543210 [ index ] (right-to-left)
|
||||
|
||||
hid.tpKeyboard[1] = uint8((hid.keyboard.con[1] << 2) | ((hid.keyboard.con[0] >> 8) & 0x03))
|
||||
hid.tpKeyboard[2] = uint8((hid.keyboard.con[2] << 4) | ((hid.keyboard.con[1] >> 6) & 0x0F))
|
||||
hid.tpKeyboard[3] = uint8((hid.keyboard.con[3] << 6) | ((hid.keyboard.con[2] >> 4) & 0x3F))
|
||||
hid.tpKeyboard[4] = uint8(hid.keyboard.con[3] >> 2)
|
||||
hid.tpKeyboard[5] = hid.keyboard.sys[0]
|
||||
hid.tpKeyboard[6] = hid.keyboard.sys[1]
|
||||
hid.tpKeyboard[7] = hid.keyboard.sys[2]
|
||||
|
||||
return d.keyboardWrite(descHIDEndpointMediaKey, hid.tpKeyboard[:])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) keyboardWrite(endpoint uint8, data []uint8) bool {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
size := uint16(len(data))
|
||||
xfer := &hid.tdKeyboard[hid.txKeyboardHead]
|
||||
when := ticks()
|
||||
for {
|
||||
if 0 == xfer.token&0x80 {
|
||||
if 0 != xfer.token&0x68 {
|
||||
// TODO: token contains error, how to handle?
|
||||
}
|
||||
hid.txKeyboardPrev = false
|
||||
break
|
||||
}
|
||||
if hid.txKeyboardPrev {
|
||||
return false
|
||||
}
|
||||
if ticks()-when > descHIDKeyboardTxTimeoutMs {
|
||||
// Waited too long, assume host connection dropped
|
||||
hid.txKeyboardPrev = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Without this delay, the order packets are transmitted is seriously screwy.
|
||||
udelay(60)
|
||||
buff := hid.txKeyboard[hid.txKeyboardHead*descHIDKeyboardTxSize:]
|
||||
_ = copy(buff, data)
|
||||
d.transferPrepare(xfer, &buff[0], size, 0)
|
||||
flushCache(uintptr(unsafe.Pointer(&buff[0])), descHIDKeyboardTxSize)
|
||||
d.endpointTransmit(endpoint, xfer)
|
||||
hid.txKeyboardHead += 1
|
||||
if hid.txKeyboardHead >= descHIDKeyboardTDCount {
|
||||
hid.txKeyboardHead = 0
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [HID] Mouse
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) mouseConfigure() {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
switch d.speed() {
|
||||
case descDeviceSpeedHigh:
|
||||
hid.txMouseSize = descHIDMouseTxHSPacketSize
|
||||
default:
|
||||
hid.txMouseSize = descHIDMouseTxFSPacketSize
|
||||
}
|
||||
|
||||
d.endpointEnable(descHIDEndpointMouse,
|
||||
false, descHIDConfigAttrMouse)
|
||||
|
||||
d.endpointConfigureTx(descHIDEndpointMouse,
|
||||
hid.txMouseSize, false, nil)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [HID] Joystick
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) joystickConfigure() {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
switch d.speed() {
|
||||
case descDeviceSpeedHigh:
|
||||
hid.txJoystickSize = descHIDJoystickTxHSPacketSize
|
||||
default:
|
||||
hid.txJoystickSize = descHIDJoystickTxFSPacketSize
|
||||
}
|
||||
|
||||
d.endpointEnable(descHIDEndpointJoystick,
|
||||
false, descHIDConfigAttrJoystick)
|
||||
|
||||
d.endpointConfigureTx(descHIDEndpointJoystick,
|
||||
hid.txJoystickSize, false, nil)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
)
|
||||
|
||||
type (
|
||||
UARTConfig struct {
|
||||
BaudRate uint32
|
||||
}
|
||||
// UART represents a virtual serial (UART) device emulation using the USB
|
||||
// CDC-ACM device class driver.
|
||||
type UART struct {
|
||||
Port int
|
||||
core *core
|
||||
}
|
||||
|
||||
// UART represents a virtual serial (UART) device emulation using the USB
|
||||
// CDC-ACM device class driver.
|
||||
UART struct {
|
||||
port int // USB port (core index, e.g., 0-1)
|
||||
core *core
|
||||
}
|
||||
)
|
||||
type UARTConfig struct {
|
||||
// Port is the MCU's native USB core number. If in doubt, leave it
|
||||
// uninitialized for default (0).
|
||||
Port int
|
||||
}
|
||||
|
||||
func (uart *UART) Configure(config UARTConfig) error {
|
||||
|
||||
if uart.port >= CoreCount || uart.port >= dcdCount {
|
||||
if config.Port >= CoreCount || config.Port >= dcdCount {
|
||||
return ErrUARTInvalidPort
|
||||
}
|
||||
uart.Port = config.Port
|
||||
|
||||
// verify we have a free USB port and take ownership of it
|
||||
var st status
|
||||
uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1})
|
||||
uart.core, st = initCore(uart.Port, class{id: classDeviceCDCACM, config: 1})
|
||||
if !st.ok() {
|
||||
return ErrUARTInvalidPort
|
||||
}
|
||||
|
||||
@@ -106,14 +106,15 @@ type class struct {
|
||||
|
||||
// Enumerated constants for all host/device class configurations.
|
||||
const (
|
||||
classDeviceCDCACM = 0 // The only currently-supported class (CDC-ACM)
|
||||
classDeviceCDCACM = 0
|
||||
classDeviceHID = 1
|
||||
)
|
||||
|
||||
// mode returns the USB core operating mode of the receiver class c.
|
||||
//go:inline
|
||||
func (c class) mode() int {
|
||||
switch c.id {
|
||||
case classDeviceCDCACM:
|
||||
case classDeviceCDCACM, classDeviceHID:
|
||||
return modeDevice
|
||||
default:
|
||||
return modeIdle
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package usb
|
||||
|
||||
//go:linkname ticks runtime.ticks
|
||||
func ticks() int64
|
||||
|
||||
// leU64 returns a slice containing 8 bytes from the given uint64 u.
|
||||
//
|
||||
// The returned bytes have little-endian ordering; that is, the first element
|
||||
@@ -214,3 +217,55 @@ func endpointIndex(address uint8) uint8 {
|
||||
return ((address & descEndptAddrNumberMsk) << 1) |
|
||||
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
|
||||
}
|
||||
|
||||
// The following buffLo and buffHi are helper methods for slice definitions from
|
||||
// potentially zero-length arrays (depending on compile-time constants).
|
||||
//
|
||||
// For example, if we have an array containing a 5-element buffer for three
|
||||
// instances of some device class (15 total elements), partitioned as follows,
|
||||
// then we compute the indices for instance 2 as usual:
|
||||
//
|
||||
// Index: 01234 56789 ABCDE
|
||||
// Array: [ 1 | 2 | 3 ]
|
||||
//
|
||||
// Lo: (n-1) * size => (2-1) * 5 => 5
|
||||
// Hi: (n) * size => (2) * 5 => 10 (0xA)
|
||||
//
|
||||
// However, if we have specified (via const definition) that 0 instances of some
|
||||
// device class be allocated, then the associated device class buffer arrays
|
||||
// will all be zero-length arrays, and the arithmetic to compute the slice
|
||||
// indices used above will result in out-of-bounds indices:
|
||||
//
|
||||
// Index:
|
||||
// Array: []
|
||||
//
|
||||
// Lo: (n-1) * size => (2-1) * 5 => 5 [Error!]
|
||||
// Hi: (n) * size => (2) * 5 => 10 (0xA) [Error!]
|
||||
//
|
||||
//
|
||||
// I couldn't figure out a straight-forward way to resolve these slice indices
|
||||
// using only arithmetic, so I've resorted to simple conditionals. If the number
|
||||
// of instances for some given class is zero (count=0), defined via compile-time
|
||||
// constant, then just use the empty slice range [0:0].
|
||||
|
||||
// buffLo returns the starting array slice index for the n'th region of size
|
||||
// elements from an array containing count regions of size elements.
|
||||
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
|
||||
// argument equals 0.
|
||||
func buffLo(n, count, size uint16) uint16 {
|
||||
if 0 == n || 0 == count || 0 == size {
|
||||
return 0
|
||||
}
|
||||
return (n - 1) * size
|
||||
}
|
||||
|
||||
// buffHi returns the ending array slice index for the n'th region of size
|
||||
// elements from an array containing count regions of size elements.
|
||||
// Regions are specified using a 1-based index (n > 0). Returns 0 if any given
|
||||
// argument equals 0.
|
||||
func buffHi(n, count, size uint16) uint16 {
|
||||
if 0 == n || 0 == count || 0 == size {
|
||||
return 0
|
||||
}
|
||||
return n * size
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ package usb
|
||||
|
||||
import "device/arm"
|
||||
|
||||
//go:linkname ticks runtime.ticks
|
||||
func ticks() int64
|
||||
|
||||
// udelay waits for the given number of microseconds before returning.
|
||||
// We cannot use the sleep timer from this context (import cycle), but we need
|
||||
// an approximate method to spin CPU cycles for short periods of time.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"device/arm"
|
||||
"device/nxp"
|
||||
"machine"
|
||||
"machine/usb"
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -125,12 +126,13 @@ func initUART() {
|
||||
}
|
||||
|
||||
func initUSB() {
|
||||
machine.UART0.Configure(machine.UARTConfig{})
|
||||
machine.HID0.Configure(usb.HIDConfig{})
|
||||
// machine.UART0.Configure(usb.UARTConfig{})
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
machine.UART0.WriteByte(c) // print to USB UART
|
||||
// machine.UART1.WriteByte(c) // print to hardware UART
|
||||
// machine.UART0.WriteByte(c) // print to USB UART
|
||||
machine.UART1.WriteByte(c) // print to hardware UART
|
||||
}
|
||||
|
||||
func abort() {
|
||||
|
||||
Reference in New Issue
Block a user