Compare commits

...

24 Commits

Author SHA1 Message Date
sago35 27a9e5d764 fix handling of DTGLIN 2022-05-30 18:18:35 +09:00
sago35 297d3cbcc2 Revert "shrink configuration descriptor"
This reverts commit b86574be9dcf261c0370cf33288e24e2382dac79.
2022-05-30 18:18:35 +09:00
sago35 2651b1d8bd fix packetComplete() 2022-05-30 18:18:35 +09:00
sago35 319b49e81c change to duplicate slice 2022-05-30 18:18:35 +09:00
sago35 7e493642eb shrink configuration descriptor 2022-05-30 18:18:35 +09:00
sago35 674b3b966f Add serial initialization 2022-05-30 18:18:35 +09:00
sago35 d9d29d3c68 add Interface Association Descriptor 2022-05-30 18:18:35 +09:00
sago35 e94ab78926 refactor USB init functions to minimize API 2022-05-30 18:18:35 +09:00
sago35 8fa58fdc6d more refactoring, verified CDC on macOS 2022-05-30 18:18:35 +09:00
sago35 4b81985d2b refactor USB package with device class build tags
added basic HID keyboard support for SAMx51 (not fully-functional)
2022-05-30 18:18:35 +09:00
ardnew 3b892cbe41 functional USB CDC-ACM for SAMx51 2022-05-30 18:18:35 +09:00
ardnew 5f6489d3cf add basic CDC-ACM UART Rx capability 2022-05-30 18:18:35 +09:00
sago35 2f50d24fec functioning USB-CDC class initialization 2022-05-30 18:18:35 +09:00
ardnew 6e29c17a8b initial file structure for SAMx51 USB device support 2022-05-30 18:18:35 +09:00
ardnew 67e68e484f set default Teensy 4.0 USB configuration to USB serial 2022-05-30 18:18:35 +09:00
ardnew 4b8b4243ec cleanup and compatibility updates from STM32H7 USB implemenetation 2022-05-30 18:18:35 +09:00
ardnew d2a1835ffc implemented USB HID composite keyboard support 2022-05-30 18:18:35 +09:00
ardnew 34b931b6f3 begin isolating target-specific USB code 2022-05-30 18:18:35 +09:00
ardnew 07964818d9 prevent heap alloc in control complete 2022-05-30 18:18:34 +09:00
ardnew 079eace344 rename package machine/usb2 to machine/usb 2022-05-30 18:18:34 +09:00
ardnew 69e8257e7b USB CDC-ACM UART Rx/Tx functioning for baseline target (Teensy 4.0/4.1) 2022-05-30 18:18:34 +09:00
ardnew 8103b3c3c8 functioning ACM device registration with host 2022-05-30 18:18:34 +09:00
ardnew a041a7866d cleanup unused code for baseline 2022-05-30 18:18:34 +09:00
ardnew 6583ec1448 begin USB refactor with package machine/usb2 2022-05-30 18:18:34 +09:00
42 changed files with 9304 additions and 841 deletions
+162 -66
View File
@@ -8,6 +8,7 @@
package nxp
import (
"device/arm"
"runtime/volatile"
"unsafe"
)
@@ -378,30 +379,6 @@ func (clk Clock) setCcm(value uint32) {
}
}
func setSysPfd(value ...uint32) {
for i, val := range value {
pfd528 := CCM_ANALOG.PFD_528.Get() &
^((CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_528_PFD0_FRAC_Msk) << (8 * uint32(i)))
frac := (val << CCM_ANALOG_PFD_528_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_528_PFD0_FRAC_Msk
// disable the clock output first
CCM_ANALOG.PFD_528.Set(pfd528 | (CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk << (8 * uint32(i))))
// set the new value and enable output
CCM_ANALOG.PFD_528.Set(pfd528 | (frac << (8 * uint32(i))))
}
}
func setUsb1Pfd(value ...uint32) {
for i, val := range value {
pfd480 := CCM_ANALOG.PFD_480.Get() &
^((CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_480_PFD0_FRAC_Msk) << (8 * uint32(i)))
frac := (val << CCM_ANALOG_PFD_480_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_480_PFD0_FRAC_Msk
// disable the clock output first
CCM_ANALOG.PFD_480.Set(pfd480 | (CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk << (8 * uint32(i))))
// set the new value and enable output
CCM_ANALOG.PFD_480.Set(pfd480 | (frac << (8 * uint32(i))))
}
}
// PLL configuration for ARM
type ClockConfigArmPll struct {
LoopDivider uint32 // PLL loop divider. Valid range for divider value: 54-108. Fout=Fin*LoopDivider/2.
@@ -472,59 +449,178 @@ func (cfg ClockConfigSysPll) Configure(pfd ...uint32) {
setSysPfd(pfd...)
}
// PLL configuration for USB
type ClockConfigUsbPll struct {
Instance uint8 // USB PLL number (1 or 2)
LoopDivider uint8 // PLL loop divider: 0 - Fout=Fref*20, 1 - Fout=Fref*22
Src uint8 // Pll clock source, reference _clock_pll_clk_src
func setSysPfd(value ...uint32) {
for i, val := range value {
pfd528 := CCM_ANALOG.PFD_528.Get() &
^((CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_528_PFD0_FRAC_Msk) << (8 * uint32(i)))
frac := (val << CCM_ANALOG_PFD_528_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_528_PFD0_FRAC_Msk
// disable the clock output first
CCM_ANALOG.PFD_528.Set(pfd528 | (CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk << (8 * uint32(i))))
// set the new value and enable output
CCM_ANALOG.PFD_528.Set(pfd528 | (frac << (8 * uint32(i))))
}
}
func (cfg ClockConfigUsbPll) Configure(pfd ...uint32) {
// PHY configuration for USB HS
type ClockConfigUsbPhy struct {
Instance uint8 // USB PHY number (1 or 2)
XtalFreq uint32 // External reference clock frequency (Hz)
DCal uint32 // Decode to trim nominal 17.78mA current source
TxCal45DP uint32 // Decode to trim nominal 45-Ohm series Rp on USB D+
TxCal45DM uint32 // Decode to trim nominal 45-Ohm series Rp on USB D-
PllConfig ClockConfigUsbPll
}
// Configure initializes the USB HS (480 Mbit/s) PHY and PLL clocks, including
// the USB +3V regulator (PMU), for use as either USB host or device.
func (cfg ClockConfigUsbPhy) Configure() {
var (
usb *USB_Type
phy *USBPHY_Type
chrgDetectReg *volatile.Register32
chrgDetectMsk uint32
)
// Select appropriate peripherals based on receiver Instance
switch cfg.Instance {
case 1:
// bypass PLL first
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk
CCM_ANALOG.PLL_USB1.Set(
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk)) |
CCM_ANALOG_PLL_USB1_BYPASS_Msk | src)
sel := uint32((cfg.LoopDivider << CCM_ANALOG_PLL_USB1_DIV_SELECT_Pos) & CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk)
CCM_ANALOG.PLL_USB1_SET.Set(
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk)) |
CCM_ANALOG_PLL_USB1_ENABLE_Msk | CCM_ANALOG_PLL_USB1_POWER_Msk |
CCM_ANALOG_PLL_USB1_EN_USB_CLKS_Msk | sel)
for !CCM_ANALOG.PLL_USB1.HasBits(CCM_ANALOG_PLL_USB1_LOCK_Msk) {
}
// disable bypass
CCM_ANALOG.PLL_USB1_CLR.Set(CCM_ANALOG_PLL_USB1_BYPASS_Msk)
// update PFDs after update
setUsb1Pfd(pfd...)
usb = USB1 // Select USB1 HS PHY/PLL
phy = USBPHY1 //
chrgDetectReg = &USB_ANALOG.USB1_CHRG_DETECT_SET
chrgDetectMsk = USB_ANALOG_USB1_CHRG_DETECT_SET_CHK_CHRG_B |
USB_ANALOG_USB1_CHRG_DETECT_SET_EN_B
case 2:
// bypass PLL first
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk
CCM_ANALOG.PLL_USB2.Set(
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk)) |
CCM_ANALOG_PLL_USB2_BYPASS_Msk | src)
usb = USB2 // Select USB2 HS PHY/PLL
phy = USBPHY2 //
chrgDetectReg = &USB_ANALOG.USB2_CHRG_DETECT_SET
chrgDetectMsk = USB_ANALOG_USB2_CHRG_DETECT_SET_CHK_CHRG_B |
USB_ANALOG_USB2_CHRG_DETECT_SET_EN_B
default:
panic("nxp: invalid USB PHY")
}
sel := uint32((cfg.LoopDivider << CCM_ANALOG_PLL_USB2_DIV_SELECT_Pos) & CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk)
CCM_ANALOG.PLL_USB2.Set(
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk)) |
CCM_ANALOG_PLL_USB2_ENABLE_Msk | CCM_ANALOG_PLL_USB2_POWER_Msk |
CCM_ANALOG_PLL_USB2_EN_USB_CLKS_Msk | sel)
// Configure and enable USB PLL clocks
cfg.PllConfig.Configure()
for !CCM_ANALOG.PLL_USB2.HasBits(CCM_ANALOG_PLL_USB2_LOCK_Msk) {
// Release PHY from reset
phy.CTRL.ClearBits(USBPHY_CTRL_SFTRST)
phy.CTRL.ClearBits(USBPHY_CTRL_CLKGATE)
// Enable power to USB PHY
phy.PWD.Set(0)
phy.CTRL.SetBits(USBPHY_CTRL_ENAUTOCLR_PHY_PWD | USBPHY_CTRL_ENAUTOCLR_CLKGATE |
// enable support for low-speed device connection, direct and indirect (hub)
USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3)
// Enable USB HS clocks gate
ClockIpUsbOh3.Enable(true)
// Reset USB peripheral
usb.USBCMD.SetBits(USB_USBCMD_RST)
// Add a delay after RST to ensure there is a USB D+ pullup sequence
nopDelay(400000)
// Enable USB LDO
PMU.REG_3P0.Set((PMU.REG_3P0.Get() & ^uint32(PMU_REG_3P0_OUTPUT_TRG_Msk)) |
(0x17 << PMU_REG_3P0_OUTPUT_TRG_Pos) | PMU_REG_3P0_ENABLE_LINREG)
// check whether we are connected to USB charger
chrgDetectReg.Set(chrgDetectMsk)
// Decode to trim nominal 17.78mA source for HS TX on USB D+/D-
phy.TX.Set((phy.TX.Get() &
^uint32(USBPHY_TX_D_CAL_Msk|USBPHY_TX_TXCAL45DN_Msk|USBPHY_TX_TXCAL45DP_Msk)) |
((cfg.DCal << USBPHY_TX_D_CAL_Pos) & USBPHY_TX_D_CAL_Msk) |
((cfg.TxCal45DM << USBPHY_TX_TXCAL45DN_Pos) & USBPHY_TX_TXCAL45DN_Msk) |
((cfg.TxCal45DP << USBPHY_TX_TXCAL45DP_Pos) & USBPHY_TX_TXCAL45DP_Msk))
}
// PLL configuration for USB
type ClockConfigUsbPll struct {
Instance uint8 // USB PLL number (1 or 2)
LoopDivider uint8 // PLL loop divider (0 [Fout=Fref*20] or 1 [Fout=Fref*22])
Src uint8 // PLL bypass clock source (0 [OSC24M] or 1 [CLK1_P & CLK1_N])
Pfd []uint32 // Phase fractional divisors (len=4, or nil for boot default)
}
func (cfg ClockConfigUsbPll) Configure() {
// select USB peripheral registers based on receiver's Instance
switch cfg.Instance {
case 1: // USB1 PLL
if CCM_ANALOG.PLL_USB1.HasBits(CCM_ANALOG_PLL_USB1_ENABLE) {
// PLL already configured, enable USB clocks
CCM_ANALOG.PLL_USB1.SetBits(CCM_ANALOG_PLL_USB1_EN_USB_CLKS)
} else {
// bypass PLL first
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Pos) &
CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk
CCM_ANALOG.PLL_USB1.Set(
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk)) |
CCM_ANALOG_PLL_USB1_BYPASS | src)
// reconfigure PLL
sel := (uint32(cfg.LoopDivider) << CCM_ANALOG_PLL_USB1_DIV_SELECT_Pos) &
CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk
CCM_ANALOG.PLL_USB1.Set(
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk)) |
CCM_ANALOG_PLL_USB1_ENABLE | CCM_ANALOG_PLL_USB1_POWER |
CCM_ANALOG_PLL_USB1_EN_USB_CLKS | sel)
for !CCM_ANALOG.PLL_USB1.HasBits(CCM_ANALOG_PLL_USB1_LOCK) {
}
// disable bypass
CCM_ANALOG.PLL_USB1.ClearBits(CCM_ANALOG_PLL_USB1_BYPASS)
// update PFDs (if provided)
if nil != cfg.Pfd {
setUsb1Pfd(cfg.Pfd...)
}
}
case 2: // USB2 PLL
if CCM_ANALOG.PLL_USB2.HasBits(CCM_ANALOG_PLL_USB2_ENABLE) {
// PLL already configured, enable USB clocks
CCM_ANALOG.PLL_USB2.SetBits(CCM_ANALOG_PLL_USB2_EN_USB_CLKS)
} else {
// bypass PLL first
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Pos) &
CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk
CCM_ANALOG.PLL_USB2.Set(
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk)) |
CCM_ANALOG_PLL_USB2_BYPASS | src)
// reconfigure PLL
sel := (uint32(cfg.LoopDivider) << CCM_ANALOG_PLL_USB2_DIV_SELECT_Pos) &
CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk
CCM_ANALOG.PLL_USB2.Set(
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk)) |
CCM_ANALOG_PLL_USB2_ENABLE | CCM_ANALOG_PLL_USB2_POWER |
CCM_ANALOG_PLL_USB2_EN_USB_CLKS | sel)
for !CCM_ANALOG.PLL_USB2.HasBits(CCM_ANALOG_PLL_USB2_LOCK) {
}
// disable bypass
CCM_ANALOG.PLL_USB2.ClearBits(CCM_ANALOG_PLL_USB2_BYPASS)
}
// disable bypass
CCM_ANALOG.PLL_USB2.ClearBits(CCM_ANALOG_PLL_USB2_BYPASS_Msk)
default:
panic("nxp: invalid USB PLL")
}
}
func setUsb1Pfd(value ...uint32) {
for i, val := range value {
pfd480 := CCM_ANALOG.PFD_480.Get() &
^((CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_480_PFD0_FRAC_Msk) << (8 * uint32(i)))
frac := (val << CCM_ANALOG_PFD_480_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_480_PFD0_FRAC_Msk
// disable the clock output first
CCM_ANALOG.PFD_480.Set(pfd480 | (CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk << (8 * uint32(i))))
// set the new value and enable output
CCM_ANALOG.PFD_480.Set(pfd480 | (frac << (8 * uint32(i))))
}
}
// We cannot use the sleep timer from this context (import cycle), but we need
// an approximate method to spin CPU cycles for short periods of time.
// go:inline
func nopDelay(cycles uint32) {
for i := uint32(0); i < cycles; i++ {
arm.Asm(`nop`)
}
}
+80
View File
@@ -252,3 +252,83 @@ func enableDcache(enable bool) {
}
}
}
// FlushDcache flushes data from cache to memory
//
// Normally FlushDcache is used when metadata written to memory will be used by
// a DMA or a bus-controller peripheral. Any data in the cache is written to
// memory. A copy remains in the cache, so this is typically used with special
// fields you will want to quickly access in the future. For data transmission,
// use FlushDeleteDcache.
//go:inline
func FlushDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCCMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
// DeleteDcache deletes data from the cache, without touching memory.
//
// Normally DeleteDcache is used before receiving data via DMA or from
// bus-controller peripherals which write to memory. You want to delete anything
// the cache may have stored, so your next read is certain to access the
// physical memory.
//go:inline
func DeleteDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCIMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
// FlushDeleteDcache flushes data from cache to memory, and delete it from the
// cache
//
// Normally FlushDeleteDcache is used when transmitting data via DMA or
// bus-controller peripherals which read from memory. You want any cached data
// written to memory, and then removed from the cache, because you no longer
// need to access the data after transmission.
//go:inline
func FlushDeleteDcache(addr, size uintptr) {
location := addr & 0xFFFFFFE0
endAddr := addr + size
arm.AsmFull(`
dsb 0xF
`, nil)
for {
SystemControl.DCCIMVAC.Set(uint32(location))
location += 32
if location >= endAddr {
break
}
}
arm.AsmFull(`
dsb 0xF
isb 0xF
`, nil)
}
View File
+258
View File
@@ -0,0 +1,258 @@
package main
import (
"machine"
"machine/usb"
"time"
)
var keyboard = machine.USB.Keyboard()
func main() {
for !machine.USB.Ready() {
}
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 (GNU screen)
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 (GNU screen)
keyboard.Down(usb.KeyModifierCtrl)
// Ctrl-X is the prefix sequence in my GNU screen configuration
keyboard.Press(usb.KeyX)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(time.Second)
// Backslash (Prefix-\) is the GNU screen command to kill window
keyboard.Press(usb.KeyBackslash)
time.Sleep(time.Second)
// Confirm "Kill window (Y/N)?" prompt
keyboard.Press(usb.KeyY)
keyboard.Press(usb.KeyEnter)
time.Sleep(2 * time.Second)
// Close terminal
keyboard.Down(usb.KeyModifierCtrl)
// Ctrl-D exits the shell (sends a resemblance of EOF, I believe?)
keyboard.Press(usb.KeyD)
keyboard.Up(usb.KeyModifierCtrl)
time.Sleep(25 * time.Second)
}
}
type Key struct {
Press usb.Keycode
Down usb.Keycode
Up usb.Keycode
Time time.Duration
}
func testKeys(key []Key, delay time.Duration) {
for _, k := range key {
if 0 != k.Down {
keyboard.Down(k.Down)
}
if 0 != k.Press {
keyboard.Press(k.Press)
}
if 0 != k.Up {
keyboard.Up(k.Up)
}
if 0 != k.Time {
time.Sleep(k.Time)
} else {
time.Sleep(delay)
}
}
}
func testInternationalLayout() {
// International keyboard layouts also supported
keyboard.Write([]byte("TinyGo USB Keyboard Layout Test\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Lowercase: abcdefghijklmnopqrstuvwxyz\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Numbers: 0123456789\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols1: !\"#$%&'()*+,-./\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols2: :;<=>?[\\]^_`{|}~\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols3: ¡¢£¤¥¦§¨©ª«¬­®¯°±\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Symbols4: ²³´µ¶·¸¹º»¼½¾¿×÷\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Grave: ÀÈÌÒÙàèìòù\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Acute: ÁÉÍÓÚÝáéíóúý\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Circumflex: ÂÊÎÔÛâêîôû\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Tilde: ÃÑÕãñõ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Diaeresis: ÄËÏÖÜäëïöüÿ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Cedilla: Çç\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Ring Above: Åå\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("AE: Ææ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Thorn: Þþ\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Sharp S: ß\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("O-Stroke: Øø\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Eth: Ðð\n"))
time.Sleep(250 * time.Millisecond)
keyboard.Write([]byte("Euro: €\n"))
}
+37
View File
@@ -0,0 +1,37 @@
// This is a echo console running on the device UART.
// Connect using default baudrate for this hardware, 8-N-1 with your terminal program.
package main
import (
"machine"
"time"
)
func main() {
uart := machine.Serial
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)
}
}
+25 -15
View File
@@ -5,6 +5,7 @@ package machine
import (
"device/nxp"
"machine/usb"
"runtime/interrupt"
)
@@ -56,21 +57,21 @@ const (
// Analog pins
const (
// = Pin // Dig | [Pad] {ADC1/ADC2}
A0 = PA18 // D14 | [AD_B1_02] { 7 / 7 }
A1 = PA19 // D15 | [AD_B1_03] { 8 / 8 }
A2 = PA23 // D16 | [AD_B1_07] { 12 / 12 }
A3 = PA22 // D17 | [AD_B1_06] { 11 / 11 }
A4 = PA17 // D18 | [AD_B1_01] { 6 / 6 }
A5 = PA16 // D19 | [AD_B1_00] { 5 / 5 }
A6 = PA26 // D20 | [AD_B1_10] { 15 / 15 }
A7 = PA27 // D21 | [AD_B1_11] { 0 / 0 }
A8 = PA24 // D22 | [AD_B1_08] { 13 / 13 }
A9 = PA25 // D23 | [AD_B1_09] { 14 / 14 }
A10 = PA12 // D24 | [AD_B0_12] { 1 / - }
A11 = PA13 // D25 | [AD_B0_13] { 2 / - }
A12 = PA30 // D26 | [AD_B1_14] { - / 3 }
A13 = PA31 // D27 | [AD_B1_15] { - / 4 }
// = Pin // Dig [Pad] {ADC1/ADC2}
A0 = PA18 // D14 [AD_B1_02] { 7 / 7 }
A1 = PA19 // D15 [AD_B1_03] { 8 / 8 }
A2 = PA23 // D16 [AD_B1_07] { 12 / 12 }
A3 = PA22 // D17 [AD_B1_06] { 11 / 11 }
A4 = PA17 // D18 [AD_B1_01] { 6 / 6 }
A5 = PA16 // D19 [AD_B1_00] { 5 / 5 }
A6 = PA26 // D20 [AD_B1_10] { 15 / 15 }
A7 = PA27 // D21 [AD_B1_11] { 0 / 0 }
A8 = PA24 // D22 [AD_B1_08] { 13 / 13 }
A9 = PA25 // D23 [AD_B1_09] { 14 / 14 }
A10 = PA12 // D24 [AD_B0_12] { 1 / - }
A11 = PA13 // D25 [AD_B0_13] { 2 / - }
A12 = PA30 // D26 [AD_B1_14] { - / 3 }
A13 = PA31 // D27 [AD_B1_15] { - / 4 }
)
// Default peripheral pins
@@ -105,6 +106,15 @@ func init() {
_UART7.Interrupt = interrupt.New(nxp.IRQ_LPUART7, _UART7.handleInterrupt)
}
// #=====================================================#
// | USB |
// #=====================================================#
var (
UART0 = usb.UART{Port: 0}
// HID0 = usb.HID{Port: 0}
// UART0 = &UART1
)
// #=====================================================#
// | UART |
// #===========#===========#=============#===============#
+2 -712
View File
@@ -13,7 +13,6 @@ import (
"device/sam"
"errors"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)
@@ -1975,719 +1974,10 @@ func (tcc *TCC) Set(channel uint8, value uint32) {
}
}
// USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
type USBCDC struct {
Buffer *RingBuffer
TxIdx volatile.Register8
waitTxc bool
waitTxcRetryCount uint8
sent bool
configured bool
}
var (
// USB is a USB CDC interface.
USB = &USBCDC{Buffer: NewRingBuffer()}
)
const (
usbcdcTxSizeMask uint8 = 0x3F
usbcdcTxBankMask uint8 = ^usbcdcTxSizeMask
usbcdcTxBank1st uint8 = 0x00
usbcdcTxBank2nd uint8 = usbcdcTxSizeMask + 1
usbcdcTxMaxRetriesAllowed uint8 = 5
)
// Flush flushes buffered data.
func (usbcdc *USBCDC) Flush() error {
if usbLineInfo.lineState > 0 {
idx := usbcdc.TxIdx.Get()
sz := idx & usbcdcTxSizeMask
bk := idx & usbcdcTxBankMask
if 0 < sz {
if usbcdc.waitTxc {
// waiting for the next flush(), because the transmission is not complete
usbcdc.waitTxcRetryCount++
return nil
}
usbcdc.waitTxc = true
usbcdc.waitTxcRetryCount = 0
// set the data
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][bk]))))
if bk == usbcdcTxBank1st {
usbcdc.TxIdx.Set(usbcdcTxBank2nd)
} else {
usbcdc.TxIdx.Set(usbcdcTxBank1st)
}
// clean multi packet size of bytes already sent
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set count of bytes to be sent
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((uint32(sz) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// clear transfer complete flag
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
// send data by setting bank ready
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
usbcdc.sent = true
}
}
return nil
}
// WriteByte writes a byte of data to the USB CDC interface.
func (usbcdc *USBCDC) WriteByte(c byte) error {
// Supposedly to handle problem with Windows USB serial ports?
if usbLineInfo.lineState > 0 {
ok := false
for {
mask := interrupt.Disable()
idx := usbcdc.TxIdx.Get()
if (idx & usbcdcTxSizeMask) < usbcdcTxSizeMask {
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][idx] = c
usbcdc.TxIdx.Set(idx + 1)
ok = true
}
interrupt.Restore(mask)
if ok {
break
} else if usbcdcTxMaxRetriesAllowed < usbcdc.waitTxcRetryCount {
mask := interrupt.Disable()
usbcdc.waitTxc = false
usbcdc.waitTxcRetryCount = 0
usbcdc.TxIdx.Set(0)
usbLineInfo.lineState = 0
interrupt.Restore(mask)
break
} else {
mask := interrupt.Disable()
if usbcdc.sent {
if usbcdc.waitTxc {
if (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) != 0 {
setEPSTATUSCLR(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
usbcdc.waitTxc = false
usbcdc.Flush()
}
} else {
usbcdc.Flush()
}
}
interrupt.Restore(mask)
}
}
}
return nil
}
func (usbcdc *USBCDC) DTR() bool {
return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0
}
func (usbcdc *USBCDC) RTS() bool {
return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0
}
const (
// these are SAMD51 specific.
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
)
var (
usbEndpointDescriptors [8]usbDeviceDescriptor
udd_ep_in_cache_buffer [7][128]uint8
udd_ep_out_cache_buffer [7][128]uint8
isEndpointHalt = false
isRemoteWakeUpEnabled = false
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn)}
usbConfiguration uint8
usbSetInterface uint8
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
)
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
func (usbcdc *USBCDC) Configure(config UARTConfig) {
// reset USB interface
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST)
for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) ||
sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) {
}
sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors))))
// configure pins
func initUSB() {
// Configure USB D+/D- pins.
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
// performs pad calibration from store fuses
handlePadCalibration()
// run in standby
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY)
// set full speed
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
// attach
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
// enable interrupt for end of reset
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST)
// enable interrupt for start of frame
sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF)
// enable USB
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
// enable IRQ at highest priority
interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
usbcdc.configured = true
}
// Configured returns whether usbcdc is configured or not.
func (usbcdc *USBCDC) Configured() bool {
return usbcdc.configured
}
func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file.
// Modeled after defines from samd21g18a.h and nvmctrl.h:
//
// #define NVMCTRL_OTP4 0x00806020
//
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
//
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
calibTransN := uint16(fuse>>13) & uint16(0x1f)
calibTransP := uint16(fuse>>18) & uint16(0x1f)
calibTrim := uint16(fuse>>23) & uint16(0x7)
if calibTransN == 0x1f {
calibTransN = 5
}
sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
if calibTransP == 0x1f {
calibTransP = 29
}
sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
if calibTrim == 0x7 {
calibTrim = 3
}
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
}
func handleUSBIRQ(interrupt.Interrupt) {
// reset all interrupt flags
flags := sam.USB_DEVICE.INTFLAG.Get()
sam.USB_DEVICE.INTFLAG.Set(flags)
// End of reset
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
// Configure control endpoint
initEndpoint(0, usb_ENDPOINT_TYPE_CONTROL)
// Enable Setup-Received interrupt
setEPINTENSET(0, sam.USB_DEVICE_ENDPOINT_EPINTENSET_RXSTP)
usbConfiguration = 0
// ack the End-Of-Reset interrupt
sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST)
}
// Start of frame
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
USB.Flush()
// if you want to blink LED showing traffic, this would be the place...
}
// Endpoint 0 Setup interrupt
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP > 0 {
// ack setup received
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP)
// parse setup
setup := newUSBSetup(udd_ep_out_cache_buffer[0][:])
// Clear the Bank 0 ready flag on Control OUT
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
ok := false
if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD {
// Standard Requests
ok = handleStandardSetup(setup)
} else {
// Class Interface Requests
if setup.wIndex == usb_CDC_ACM_INTERFACE {
ok = cdcSetup(setup)
}
}
if ok {
// set Bank1 ready
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
} else {
// Stall endpoint
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
}
if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1 > 0 {
// ack the stall
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1)
// clear stall request
setEPINTENCLR(0, sam.USB_DEVICE_ENDPOINT_EPINTENCLR_STALL1)
}
}
// Now the actual transfer handlers, ignore endpoint number 0 (setup)
var i uint32
for i = 1; i < uint32(len(endPoints)); i++ {
// Check if endpoint has a pending interrupt
epFlags := getEPINTFLAG(i)
if (epFlags&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) > 0 ||
(epFlags&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) > 0 {
switch i {
case usb_CDC_ENDPOINT_OUT:
handleEndpoint(i)
setEPINTFLAG(i, epFlags)
case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM:
setEPSTATUSCLR(i, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
if i == usb_CDC_ENDPOINT_IN {
USB.waitTxc = false
}
}
}
}
}
func initEndpoint(ep, config uint32) {
switch config {
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
// set endpoint type
setEPCFG(ep, ((usb_ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
case usb_ENDPOINT_TYPE_BULK | usbEndpointOut:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
// set endpoint type
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
// receive interrupts when current transfer complete
setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
// set byte count to zero, we have not received anything yet
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// ready for next transfer
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointOut:
// TODO: not really anything, seems like...
case usb_ENDPOINT_TYPE_BULK | usbEndpointIn:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
// set endpoint type
setEPCFG(ep, ((usb_ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
// NAK on endpoint IN, the bank is not yet filled in.
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
case usb_ENDPOINT_TYPE_CONTROL:
// Control OUT
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep]))))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos))
// Control IN
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos))
// Prepare OUT endpoint for receive
// set multi packet size for expected number of receive bytes on control OUT
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count to zero, we have not received anything yet
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// NAK on endpoint OUT to show we are ready to receive control data
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK0RDY)
}
}
func handleStandardSetup(setup usbSetup) bool {
switch setup.bRequest {
case usb_GET_STATUS:
buf := []byte{0, 0}
if setup.bmRequestType != 0 { // endpoint
// TODO: actually check if the endpoint in question is currently halted
if isEndpointHalt {
buf[0] = 1
}
}
sendUSBPacket(0, buf)
return true
case usb_CLEAR_FEATURE:
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = false
} else if setup.wValueL == 0 { // ENDPOINTHALT
isEndpointHalt = false
}
sendZlp()
return true
case usb_SET_FEATURE:
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = true
} else if setup.wValueL == 0 { // ENDPOINTHALT
isEndpointHalt = true
}
sendZlp()
return true
case usb_SET_ADDRESS:
// set packet size 64 with auto Zlp after transfer
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.Set((epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) |
uint32(1<<31)) // autozlp
// ack the transfer is complete from the request
setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
// set bank ready for data
setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
// wait for transfer to complete
timeout := 3000
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
timeout--
if timeout == 0 {
return true
}
}
// last, set the device address to that requested by host
sam.USB_DEVICE.DADD.SetBits(setup.wValueL)
sam.USB_DEVICE.DADD.SetBits(sam.USB_DEVICE_DADD_ADDEN)
return true
case usb_GET_DESCRIPTOR:
sendDescriptor(setup)
return true
case usb_SET_DESCRIPTOR:
return false
case usb_GET_CONFIGURATION:
buff := []byte{usbConfiguration}
sendUSBPacket(0, buff)
return true
case usb_SET_CONFIGURATION:
if setup.bmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
for i := 1; i < len(endPoints); i++ {
initEndpoint(uint32(i), endPoints[i])
}
usbConfiguration = setup.wValueL
// Enable interrupt for CDC control messages from host (OUT packet)
setEPINTENSET(usb_CDC_ENDPOINT_ACM, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
// Enable interrupt for CDC data messages from host
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
sendZlp()
return true
} else {
return false
}
case usb_GET_INTERFACE:
buff := []byte{usbSetInterface}
sendUSBPacket(0, buff)
return true
case usb_SET_INTERFACE:
usbSetInterface = setup.wValueL
sendZlp()
return true
default:
return true
}
}
func cdcSetup(setup usbSetup) bool {
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_GET_LINE_CODING {
var b [cdcLineInfoSize]byte
b[0] = byte(usbLineInfo.dwDTERate)
b[1] = byte(usbLineInfo.dwDTERate >> 8)
b[2] = byte(usbLineInfo.dwDTERate >> 16)
b[3] = byte(usbLineInfo.dwDTERate >> 24)
b[4] = byte(usbLineInfo.bCharFormat)
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
sendUSBPacket(0, b[:])
return true
}
}
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_SET_LINE_CODING {
b, err := receiveUSBControlPacket()
if err != nil {
return false
}
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
usbLineInfo.bCharFormat = b[4]
usbLineInfo.bParityType = b[5]
usbLineInfo.bDataBits = b[6]
}
if setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
usbLineInfo.lineState = setup.wValueL
}
if setup.bRequest == usb_CDC_SET_LINE_CODING || setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
// auto-reset into the bootloader
if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 {
ResetProcessor()
} else {
// TODO: cancel any reset
}
sendZlp()
}
if setup.bRequest == usb_CDC_SEND_BREAK {
// TODO: something with this value?
// breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
// return false;
sendZlp()
}
return true
}
return false
}
//go:noinline
func sendUSBPacket(ep uint32, data []byte) {
copy(udd_ep_in_cache_buffer[ep][:], data)
// Set endpoint address for sending data
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
// clear multi-packet size which is total bytes already sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
}
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
var b [cdcLineInfoSize]byte
// address
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
// set byte count to zero
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// set ready for next data
setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
// Wait until OUT transfer is ready.
timeout := 300000
for (getEPSTATUS(0) & sam.USB_DEVICE_ENDPOINT_EPSTATUS_BK0RDY) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
}
}
// Wait until OUT transfer is completed.
timeout = 300000
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
}
}
// get data
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
if bytesread != cdcLineInfoSize {
return b, errUSBCDCBytesRead
}
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
return b, nil
}
func handleEndpoint(ep uint32) {
// get data
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
// move to ring buffer
for i := 0; i < count; i++ {
USB.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
}
// set byte count to zero
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// set multi packet size to 64
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set ready for next data
setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY)
}
func sendZlp() {
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func epPacketSize(size uint16) uint32 {
switch size {
case 8:
return 0
case 16:
return 1
case 32:
return 2
case 64:
return 3
case 128:
return 4
case 256:
return 5
case 512:
return 6
case 1023:
return 7
default:
return 0
}
}
func getEPCFG(ep uint32) uint8 {
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Get()
}
func setEPCFG(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Set(val)
}
func setEPSTATUSCLR(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSCLR.Set(val)
}
func setEPSTATUSSET(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSSET.Set(val)
}
func getEPSTATUS(ep uint32) uint8 {
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUS.Get()
}
func getEPINTFLAG(ep uint32) uint8 {
return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
}
func setEPINTFLAG(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(val)
}
func setEPINTENCLR(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENCLR.Set(val)
}
func setEPINTENSET(ep uint32, val uint8) {
sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENSET.Set(val)
}
// ResetProcessor should perform a system reset in preparation
+3
View File
@@ -5,3 +5,6 @@ package machine
// Serial is a null device: writes to it are ignored.
var Serial = NullSerial{}
func InitSerial() {
}
+4
View File
@@ -5,3 +5,7 @@ package machine
// Serial is implemented via the default (usually the first) UART on the chip.
var Serial = DefaultUART
func InitSerial() {
Serial.Configure(UARTConfig{})
}
+3
View File
@@ -5,3 +5,6 @@ package machine
// Serial is implemented via USB (USB-CDC).
var Serial = USB
func InitSerial() {
}
+13
View File
@@ -0,0 +1,13 @@
//go:build usb.cdc
// +build usb.cdc
package machine
import "machine/usb"
var USB = &usb.CDC{}
func InitUSB() {
initUSB()
USB.Configure(usb.CDCConfig{})
}
+13
View File
@@ -0,0 +1,13 @@
//go:build usb.hid
// +build usb.hid
package machine
import "machine/usb"
var USB = &usb.HID{}
func InitUSB() {
initUSB()
USB.Configure(usb.HIDConfig{})
}
+2 -2
View File
@@ -1,5 +1,5 @@
//go:build sam || nrf52840
// +build sam nrf52840
//go:build nrf52840
// +build nrf52840
package machine
+277
View File
@@ -0,0 +1,277 @@
//go:build usb.cdc
// +build usb.cdc
package usb
import "unsafe"
//go:inline
func (d *dcd) endpointMaxPacketSize(endpoint uint8) uint32 {
switch endpointNumber(endpoint) {
case descCDCEndpointCtrl:
return descControlPacketSize
case descCDCEndpointStatus:
return descCDCStatusPacketSize
case descCDCEndpointDataRx:
return descCDCDataRxPacketSize
case descCDCEndpointDataTx:
return descCDCDataTxPacketSize
}
return descControlPacketSize
}
//go:inline
func (d *dcd) controlEndpoint() uint8 {
return descCDCEndpointCtrl
}
func (d *dcd) controlSetConfiguration() {
d.cdcConfigure()
}
func (d *dcd) controlClassRequest(sup dcdSetup) dcdStage {
// Switch on the recepient and direction of the request
switch sup.bmRequestType &
(descRequestTypeRecipientMsk | descRequestTypeDirMsk) {
// --- INTERFACE Rx (OUT) ---
case descRequestTypeRecipientInterface | descRequestTypeDirOut:
// Identify which request was received
switch sup.bRequest {
// CDC | SET LINE CODING (0x20):
case descCDCRequestSetLineCoding:
// line coding must contain exactly 7 bytes
if uint16(descCDCLineCodingSize) == sup.wLength {
d.controlReceive(
uintptr(unsafe.Pointer(&descCDC[d.cc.config-1].cx[0])),
uint32(descCDCLineCodingSize), true)
// CDC Line Coding packet receipt handling occurs in method
// controlComplete().
return dcdStageDataOut
}
// CDC | SET CONTROL LINE STATE (0x22):
case descCDCRequestSetControlLineState:
// Determine interface destination of the request
switch sup.wIndex {
// Control/status interface:
case descCDCInterfaceCtrl:
// CDC Control Line State packet receipt handling occurs in method
// controlComplete().
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
default:
// Unhandled device interface
}
// CDC | SEND BREAK (0x23):
case descCDCRequestSendBreak:
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
default:
// Unhandled request
}
default:
// Unhandled request recepient or direction
}
return dcdStageStall
}
func (d *dcd) controlGetInterfaceDescriptor(sup dcdSetup) bool {
switch sup.bRequest {
// GET DESCRIPTOR (0x06):
case descRequestStandardGetDescriptor:
d.controlGetDescriptor(sup)
return true
}
return false
}
func (d *dcd) controlGetDescriptor(sup dcdSetup) {
acm := &descCDC[d.cc.config-1]
dxn := uint8(0)
// Determine the type of descriptor being requested
switch sup.wValue >> 8 {
// Device descriptor
case descTypeDevice:
dxn = descLengthDevice
_ = copy(acm.dx[:], acm.device[:dxn])
// Configuration descriptor
case descTypeConfigure:
dxn = uint8(descCDCConfigSize)
_ = 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) {
// 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 {
// 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 + " 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
}
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)
}
}
// controlComplete handles the setup completion of control endpoint 0.
func (d *dcd) controlComplete() {
// First, switch on the type of request (standard, class, or vendor)
switch d.setup.bmRequestType & descRequestTypeTypeMsk {
// === CLASS REQUEST ===
case descRequestTypeTypeClass:
// Switch on the recepient and direction of the request
switch d.setup.bmRequestType &
(descRequestTypeRecipientMsk | descRequestTypeDirMsk) {
// --- INTERFACE Rx (OUT) ---
case descRequestTypeRecipientInterface | descRequestTypeDirOut:
// Identify which request was received
switch d.setup.bRequest {
// CDC | SET LINE CODING (0x20):
case descCDCRequestSetLineCoding:
acm := &descCDC[d.cc.config-1]
// Determine interface destination of the request
switch d.setup.wIndex {
// CDC-ACM Control Interface:
case descCDCInterfaceCtrl:
// Notify PHY to handle triggers like special baud rates, which
// signal to reboot into bootloader or begin receiving OTA updates
d.cdcSetLineCoding(acm.cx[:])
default:
// Unhandled device interface
}
// CDC | SET CONTROL LINE STATE (0x22):
case descCDCRequestSetControlLineState:
// Determine interface destination of the request
switch d.setup.wIndex {
// Control/status interface:
case descCDCInterfaceCtrl:
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
d.cdcSetLineState(d.setup.wValue)
default:
// Unhandled device interface
}
default:
// Unhandled request
}
default:
// Unhandled recepient or direction
}
default:
// Unhandled request type
}
}
+375
View File
@@ -0,0 +1,375 @@
//go:build usb.hid
// +build usb.hid
package usb
import "unsafe"
//go:inline
func (d *dcd) endpointMaxPacketSize(endpoint uint8) uint32 {
switch endpointNumber(endpoint) {
case descHIDEndpointCtrl:
return descControlPacketSize
case descHIDEndpointKeyboard:
return descHIDKeyboardTxPacketSize
case descHIDEndpointMouse:
return descHIDMouseTxPacketSize
case descHIDEndpointSerialRx: // == descHIDEndpointSerialTx
switch endpoint {
case rxEndpoint(endpoint):
return descHIDSerialRxPacketSize
case txEndpoint(endpoint):
return descHIDSerialTxPacketSize
}
case descHIDEndpointJoystick:
return descHIDJoystickTxPacketSize
case descHIDEndpointMediaKey:
return descHIDMediaKeyTxPacketSize
}
return descControlPacketSize
}
//go:inline
func (d *dcd) controlEndpoint() uint8 {
return descHIDEndpointCtrl
}
//go:inline
func (d *dcd) controlSetConfiguration() {
d.serialConfigure()
d.keyboardConfigure()
d.mouseConfigure()
d.joystickConfigure()
}
func (d *dcd) controlClassRequest(sup dcdSetup) dcdStage {
// Switch on the recepient and direction of the request
switch sup.bmRequestType &
(descRequestTypeRecipientMsk | descRequestTypeDirMsk) {
// --- INTERFACE Rx (OUT) ---
case descRequestTypeRecipientInterface | descRequestTypeDirOut:
// Identify which request was received
switch sup.bRequest {
// HID | SET REPORT (0x09)
case descHIDRequestSetReport:
if sup.wLength <= descHIDSxSize {
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 dcdStageDataOut
}
// HID | SET IDLE (0x0A)
case descHIDRequestSetIdle:
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 dcdStageStatusOut
default:
// Unhandled request
}
// --- INTERFACE Tx (IN) ---
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
// Identify which request was received
switch sup.bRequest {
// HID | GET REPORT (0x01)
case descHIDRequestGetReport:
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.controlTransmit(
d.controlStatusBuffer([]uint8{0, 0}),
2, false)
return dcdStageDataIn
default:
// Unhandled request
}
default:
// Unhandled request recepient or direction
}
return dcdStageStall
}
func (d *dcd) controlGetInterfaceDescriptor(sup dcdSetup) bool {
switch sup.bRequest {
// GET DESCRIPTOR (0x06):
case descRequestStandardGetDescriptor:
d.controlGetDescriptor(sup)
return true
// GET HID REPORT (0x01):
case descHIDRequestGetReport:
d.controlGetDescriptor(sup)
return true
}
return false
}
func (d *dcd) controlGetDescriptor(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
}
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 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)
}
}
// controlComplete handles the setup completion of control endpoint 0.
func (d *dcd) controlComplete() {
// First, switch on the type of request (standard, class, or vendor)
switch d.setup.bmRequestType & descRequestTypeTypeMsk {
// === CLASS REQUEST ===
case descRequestTypeTypeClass:
// Switch on the recepient and direction of the request
switch d.setup.bmRequestType &
(descRequestTypeRecipientMsk | descRequestTypeDirMsk) {
// --- INTERFACE Rx (OUT) ---
case descRequestTypeRecipientInterface | descRequestTypeDirOut:
// Identify which request was received
switch d.setup.bRequest {
// HID | SET REPORT (0x09)
case descHIDRequestSetReport:
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 request
}
default:
// Unhandled recepient or direction
}
default:
// Unhandled request type
}
}
+428
View File
@@ -0,0 +1,428 @@
package usb
// Implementation of target-agnostic USB device controller driver (dcd).
//
// The types, constants, and methods defined in this unit are applicable to all
// targets. It was designed to complement the device hardware abstraction (dhw)
// implemented for each target, providing common/shared functionality and
// defining a standard interface with which the dhw must adhere.
import (
"runtime/volatile"
"unsafe"
)
// 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 = descCDCCount + descHIDCount
// dcdInstance provides statically-allocated instances of each USB device
// controller configured on this platform.
var dcdInstance [dcdCount]dcd
// dhwInstance provides statically-allocated instances of each USB hardware
// abstraction for ports configured as device on this platform.
var dhwInstance [dcdCount]dhw
// dcd implements a generic USB device controller driver (dcd) for all targets.
type dcd struct {
*dhw // USB hardware abstraction layer
core *core // Parent USB core this instance is attached to
port int // USB port index
cc class // USB device class
id int // USB device controller index
st volatile.Register8 // USB device state
}
// initDCD initializes and assigns a free device controller instance to the
// given USB port. Returns the initialized device controller or nil if no free
// device controller instances remain.
func initDCD(port int, speed Speed, class class) (*dcd, status) {
if 0 == dcdCount {
return nil, statusInvalid // Must have defined device controllers
}
switch class.id {
case classDeviceCDC:
if 0 == class.config || class.config > descCDCCount {
return nil, statusInvalid // Must have defined descriptors
}
default:
}
// Return the first instance whose assigned core is currently nil.
for i := range dcdInstance {
if nil == dcdInstance[i].core {
// Initialize device controller.
dcdInstance[i].dhw = allocDHW(port, i, speed, &dcdInstance[i])
dcdInstance[i].core = &coreInstance[port]
dcdInstance[i].port = port
dcdInstance[i].cc = class
dcdInstance[i].id = i
dcdInstance[i].setState(dcdStateNotReady)
return &dcdInstance[i], statusOK
}
}
return nil, statusBusy // No free device controller instances available.
}
// class returns the receiver's current device class configuration.
func (d *dcd) class() class { return d.cc }
// dcdSetupSize defines the size (bytes) of a USB standard setup packet.
const dcdSetupSize = unsafe.Sizeof(dcdSetup{}) // 8 bytes
// dcdSetup contains the USB standard setup packet used to configure a device.
type dcdSetup struct {
bmRequestType uint8
bRequest uint8
wValue uint16
wIndex uint16
wLength uint16
}
// setupFrom decodes and returns a USB standard setup packet located at the
// memory address pointed to by addr.
func setupFrom(addr uintptr) (s dcdSetup) {
var u uint64
for i := uintptr(0); i < dcdSetupSize; i++ {
u |= uint64(*(*uint8)(unsafe.Pointer(addr + i))) << (i << 3)
}
s.set(u)
return
}
// setup decodes and returns a USB standard setup packet stored in the given
// byte slice b.
func setup(b []uint8) dcdSetup {
if len(b) >= int(dcdSetupSize) {
return dcdSetup{
bmRequestType: b[0],
bRequest: b[1],
wValue: packU16(b[2:]),
wIndex: packU16(b[4:]),
wLength: packU16(b[6:]),
}
}
return dcdSetup{}
}
//go:inline
func (s *dcdSetup) set(u uint64) {
s.bmRequestType = uint8(u & 0xFF)
s.bRequest = uint8((u & 0xFF00) >> 8)
s.wValue = uint16((u & 0xFFFF0000) >> 16)
s.wIndex = uint16((u & 0xFFFF00000000) >> 32)
s.wLength = uint16((u & 0xFFFF000000000000) >> 48)
}
// pack returns the receiver USB standard setup packet s encoded as uint64.
//go:inline
func (s dcdSetup) pack() uint64 {
return ((uint64(s.bmRequestType) & 0xFF) << 0) |
((uint64(s.bRequest) & 0xFF) << 8) |
((uint64(s.wValue) & 0xFFFF) << 16) |
((uint64(s.wIndex) & 0xFFFF) << 32) |
((uint64(s.wLength) & 0xFFFF) << 48)
}
// direction parses the direction bit from the bmRequestType field of a SETUP
// packet, returning 0 for OUT (Rx) and 1 for IN (Tx) requests.
//go:inline
func (s dcdSetup) direction() uint8 {
return (s.bmRequestType & descRequestTypeDirMsk) >> descRequestTypeDirPos
}
//go:inline
func (s dcdSetup) equals(t dcdSetup) bool {
return s.bmRequestType == t.bmRequestType && s.bRequest == t.bRequest &&
s.wValue == t.wValue && s.wIndex == t.wIndex && s.wLength == t.wLength
}
// dcdState defines the current state of the device class driver.
type dcdState uint8
const (
dcdStateNotReady dcdState = iota // initial state, before END_OF_RESET
dcdStateDefault // after END_OF_RESET, before SET_ADDRESS
dcdStateAddressed // after SET_ADDRESS, before SET_CONFIGURATION
dcdStateConfigured // after SET_CONFIGURATION, operational state
dcdStateSuspended // while operational, after SUSPEND
)
func (d *dcd) state() dcdState { return dcdState(d.st.Get()) }
func (d *dcd) setState(state dcdState) (ok bool) {
curr := d.state()
switch state {
case dcdStateNotReady:
ok = true
case dcdStateDefault:
ok = curr == dcdStateNotReady || curr == dcdStateDefault
case dcdStateAddressed:
ok = curr == dcdStateDefault
case dcdStateConfigured:
ok = curr == dcdStateAddressed || curr == dcdStateConfigured || curr == dcdStateSuspended
case dcdStateSuspended:
ok = curr == dcdStateAddressed || curr == dcdStateConfigured || curr == dcdStateSuspended
default:
ok = false
}
if ok {
d.st.Set(uint8(state))
}
return
}
// dcdEvent is used to describe virtual interrupts on the USB bus to a device
// controller.
//
// Since the device controller software is intended for use with multiple TinyGo
// targets, all of which may not have exactly the same USB bus interrupts, a
// "virtual interrupt" is defined that is common to all targets. The target's
// hardware implementation (type dhw) is responsible for translating real system
// interrupts it receives into the appropriate virtual interrupt code, defined
// below, and notifying the device controller via method (*dcd).event(dcdEvent).
type dcdEvent struct {
id uint8
setup dcdSetup
mask uint32
}
// Enumerated constants for all possible USB device controller interrupt codes.
const (
dcdEventInvalid uint8 = iota // Invalid interrupt
dcdEventStatusReset // USB RESET received
dcdEventStatusResume // USB RESUME condition
dcdEventStatusSuspend // USB SUSPEND received
dcdEventStatusError // USB error condition detected on bus
dcdEventDeviceReady // USB PHY powered and ready to _go_
dcdEventDeviceAddress // USB device SET_ADDRESS complete
dcdEventDeviceConfiguration // USB device SET_CONFIGURATION complete
dcdEventControlSetup // USB SETUP received
dcdEventControlComplete // USB control request complete
dcdEventTransferComplete // USB data transfer complete
dcdEventTimer // USB (system) timer
)
func (d *dcd) event(ev dcdEvent) {
switch ev.id {
case dcdEventStatusReset:
d.setState(dcdStateNotReady)
case dcdEventStatusResume:
d.setState(dcdStateConfigured)
case dcdEventStatusSuspend:
d.setState(dcdStateSuspended)
case dcdEventDeviceReady:
if d.setState(dcdStateDefault) {
// Configure and enable control endpoint 0
d.endpointEnable(0, true, 0)
}
case dcdEventDeviceAddress:
// -- ** IMPORTANT ** --
// dcdEventDeviceAddress must be triggered by the target driver, because
// different MCUs require setting the device address at different times
// during the enumeration process.
d.setState(dcdStateAddressed)
case dcdEventDeviceConfiguration:
d.setState(dcdStateConfigured)
case dcdEventControlSetup:
// On control endpoint 0 setup events, the ev.setup field will be defined.
// We overwrite the receiver's setup field, leaving it unmodified throughout
// all transactions of a control transfer. It is only cleared once the
// completion event dcdEventControlComplete has been called and finished
// processing, or if its initial processing fails due to error.
d.setup = ev.setup
d.stage = d.controlSetup(ev.setup)
switch d.stage {
case dcdStageDataIn, dcdStageDataOut:
// TBD: control endpoint data transfer
case dcdStageStatusIn, dcdStageStatusOut:
// TBD: control endpoint status transfer
case dcdStageStall:
d.controlStall(true, ev.setup.direction())
case dcdStageSetup:
fallthrough
default:
// TBD: no stage transition occurred
}
case dcdEventControlComplete:
d.controlComplete()
// clear the active SETUP packet once the control transfer completes.
d.setup = dcdSetup{}
case dcdEventTransferComplete:
// TBD: data endpoint transfer complete
case dcdEventInvalid, dcdEventStatusError, dcdEventTimer:
fallthrough
default:
// TBD: unhandled events
}
}
// dcdStage represents the stage of a USB control transfer.
type dcdStage uint8
// Enumerated constants for all possible USB control transfer stages.
const (
dcdStageSetup dcdStage = iota // Indicates no stage transition required
dcdStageDataIn // IN data transfer
dcdStageDataOut // OUT data transfer
dcdStageStatusIn // IN status request
dcdStageStatusOut // OUT status request
dcdStageStall // Unhandled or invalid request
)
// controlSetup handles setup messages on control endpoint 0.
func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// First, switch on the type of request (standard, class, or vendor)
switch sup.bmRequestType & descRequestTypeTypeMsk {
// === STANDARD REQUEST ===
case descRequestTypeTypeStandard:
// Switch on the recepient and direction of the request
switch sup.bmRequestType &
(descRequestTypeRecipientMsk | descRequestTypeDirMsk) {
// --- DEVICE Rx (OUT) ---
case descRequestTypeRecipientDevice | descRequestTypeDirOut:
// Identify which request was received
switch sup.bRequest {
// SET ADDRESS (0x05):
case descRequestStandardSetAddress:
d.setDeviceAddress(sup.wValue)
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
// SET CONFIGURATION (0x09):
case descRequestStandardSetConfiguration:
d.cc.config = int(sup.wValue)
if 0 == d.cc.config || d.cc.config > dcdCount {
// Use default if invalid index received
d.cc.config = 1
}
d.event(dcdEvent{id: dcdEventDeviceConfiguration})
d.controlSetConfiguration()
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
default:
// Unhandled request
}
// --- DEVICE Tx (IN) ---
case descRequestTypeRecipientDevice | descRequestTypeDirIn:
// Identify which request was received
switch sup.bRequest {
// GET STATUS (0x00):
case descRequestStandardGetStatus:
d.controlTransmit(
d.controlStatusBuffer([]uint8{0, 0}),
2, false)
return dcdStageDataIn
// GET DESCRIPTOR (0x06):
case descRequestStandardGetDescriptor:
d.controlGetDescriptor(sup)
return dcdStageDataIn
// GET CONFIGURATION (0x08):
case descRequestStandardGetConfiguration:
d.controlTransmit(
d.controlStatusBuffer([]uint8{
uint8(d.cc.config),
}),
1, false)
return dcdStageDataIn
default:
// Unhandled request
}
// --- INTERFACE Tx (IN) ---
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
if d.controlGetInterfaceDescriptor(sup) {
return dcdStageDataIn
}
// --- ENDPOINT Rx (OUT) ---
case descRequestTypeRecipientEndpoint | descRequestTypeDirOut:
// Identify which request was received
switch sup.bRequest {
// CLEAR FEATURE (0x01):
case descRequestStandardClearFeature:
d.endpointClearFeature(uint8(sup.wIndex))
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
// SET FEATURE (0x03):
case descRequestStandardSetFeature:
d.endpointSetFeature(uint8(sup.wIndex))
d.controlReceive(uintptr(0), 0, false)
return dcdStageStatusOut
default:
// Unhandled request
}
// --- ENDPOINT Tx (IN) ---
case descRequestTypeRecipientEndpoint | descRequestTypeDirIn:
// Identify which request was received
switch sup.bRequest {
// GET STATUS (0x00):
case descRequestStandardGetStatus:
status := d.endpointStatus(uint8(sup.wIndex))
d.controlTransmit(
d.controlStatusBuffer([]uint8{
uint8(status),
uint8(status >> 8),
}),
2, false)
return dcdStageDataIn
default:
// Unhandled request
}
default:
// Unhandled request recepient or direction
}
// === CLASS REQUEST ===
case descRequestTypeTypeClass:
// Forward all class requests to the device class implementation.
return d.controlClassRequest(sup)
case descRequestTypeTypeVendor:
default:
// Unhandled request type
}
// All successful requests return early. If we reach this point, the request
// was invalid or unhandled. Stall the endpoint.
return dcdStageStall
}
+414
View File
@@ -0,0 +1,414 @@
//go:build usb.cdc
// +build usb.cdc
package usb
// descHIDCount defines the number of USB cores that may be configured as a
// composite (keyboard + mouse + joystick) human interface device (HID).
const descHIDCount = 0
// USB CDC constants defined per specification.
const (
// Device class
descCDCTypeComm = 0x02 // communication/control
descCDCTypeData = 0x0A // data
// Communication/control subclass
descCDCSubNone = 0x00
descCDCSubDirectLineControl = 0x01
descCDCSubAbstractControl = 0x02
descCDCSubTelephoneControl = 0x03
descCDCSubMultiChannelControl = 0x04
descCDCSubCAPIControl = 0x05
descCDCSubEthernetNetworkingControl = 0x06
descCDCSubATMNetworkingControl = 0x07
descCDCSubWirelessHandsetControl = 0x08
descCDCSubDeviceManagement = 0x09
descCDCSubMobileDirectLine = 0x0A
descCDCSubOBEX = 0x0B
descCDCSubEthernetEmulation = 0x0C
// Communication/control protocol
descCDCProtoNone = 0x00 // also for data class
descCDCProtoAT250 = 0x01
descCDCProtoATPCCA101 = 0x02
descCDCProtoATPCCA101AnnexO = 0x03
descCDCProtoATGSM707 = 0x04
descCDCProtoAT3GPP27007 = 0x05
descCDCProtoATTIACDMA = 0x06
descCDCProtoEthernetEmulation = 0x07
descCDCProtoExternal = 0xFE
descCDCProtoVendorSpecific = 0xFF // also for data class
// Data protocol
descCDCProtoPyhsicalInterface = 0x30
descCDCProtoHDLC = 0x31
descCDCProtoTransparent = 0x32
descCDCProtoManagement = 0x50
descCDCProtoDataLinkQ931 = 0x51
descCDCProtoDataLinkQ921 = 0x52
descCDCProtoDataCompressionV42BIS = 0x90
descCDCProtoEuroISDN = 0x91
descCDCProtoRateAdaptionISDNV24 = 0x92
descCDCProtoCAPICommands = 0x93
descCDCProtoHostBasedDriver = 0xFD
descCDCProtoUnitFunctional = 0xFE
// Functional descriptor length
descCDCFuncLengthHeader = 5
descCDCFuncLengthCallManagement = 5
descCDCFuncLengthAbstractControl = 4
descCDCFuncLengthUnion = 5
// Functional descriptor type
descCDCFuncTypeHeader = 0x00
descCDCFuncTypeCallManagement = 0x01
descCDCFuncTypeAbstractControl = 0x02
descCDCFuncTypeDirectLine = 0x03
descCDCFuncTypeTelephoneRinger = 0x04
descCDCFuncTypeTelephoneReport = 0x05
descCDCFuncTypeUnion = 0x06
descCDCFuncTypeCountrySelect = 0x07
descCDCFuncTypeTelephoneModes = 0x08
descCDCFuncTypeTerminal = 0x09
descCDCFuncTypeNetworkChannel = 0x0A
descCDCFuncTypeProtocolUnit = 0x0B
descCDCFuncTypeExtensionUnit = 0x0C
descCDCFuncTypeMultiChannel = 0x0D
descCDCFuncTypeCAPIControl = 0x0E
descCDCFuncTypeEthernetNetworking = 0x0F
descCDCFuncTypeATMNetworking = 0x10
descCDCFuncTypeWirelessControl = 0x11
descCDCFuncTypeMobileDirectLine = 0x12
descCDCFuncTypeMDLMDetail = 0x13
descCDCFuncTypeDeviceManagement = 0x14
descCDCFuncTypeOBEX = 0x15
descCDCFuncTypeCommandSet = 0x16
descCDCFuncTypeCommandSetDetail = 0x17
descCDCFuncTypeTelephoneControl = 0x18
descCDCFuncTypeOBEXServiceID = 0x19
// Standard request
descCDCRequestSendEncapsulatedCommand = 0x00 // CDC request SEND_ENCAPSULATED_COMMAND
descCDCRequestGetEncapsulatedResponse = 0x01 // CDC request GET_ENCAPSULATED_RESPONSE
descCDCRequestSetCommFeature = 0x02 // CDC request SET_COMM_FEATURE
descCDCRequestGetCommFeature = 0x03 // CDC request GET_COMM_FEATURE
descCDCRequestClearCommFeature = 0x04 // CDC request CLEAR_COMM_FEATURE
descCDCRequestSetAuxLineState = 0x10 // CDC request SET_AUX_LINE_STATE
descCDCRequestSetHookState = 0x11 // CDC request SET_HOOK_STATE
descCDCRequestPulseSetup = 0x12 // CDC request PULSE_SETUP
descCDCRequestSendPulse = 0x13 // CDC request SEND_PULSE
descCDCRequestSetPulseTime = 0x14 // CDC request SET_PULSE_TIME
descCDCRequestRingAuxJack = 0x15 // CDC request RING_AUX_JACK
descCDCRequestSetLineCoding = 0x20 // CDC request SET_LINE_CODING
descCDCRequestGetLineCoding = 0x21 // CDC request GET_LINE_CODING
descCDCRequestSetControlLineState = 0x22 // CDC request SET_CONTROL_LINE_STATE
descCDCRequestSendBreak = 0x23 // CDC request SEND_BREAK
descCDCRequestSetRingerParams = 0x30 // CDC request SET_RINGER_PARAMS
descCDCRequestGetRingerParams = 0x31 // CDC request GET_RINGER_PARAMS
descCDCRequestSetOperationParam = 0x32 // CDC request SET_OPERATION_PARAM
descCDCRequestGetOperationParam = 0x33 // CDC request GET_OPERATION_PARAM
descCDCRequestSetLineParams = 0x34 // CDC request SET_LINE_PARAMS
descCDCRequestGetLineParams = 0x35 // CDC request GET_LINE_PARAMS
descCDCRequestDialDigits = 0x36 // CDC request DIAL_DIGITS
descCDCRequestSetUnitParameter = 0x37 // CDC request SET_UNIT_PARAMETER
descCDCRequestGetUnitParameter = 0x38 // CDC request GET_UNIT_PARAMETER
descCDCRequestClearUnitParameter = 0x39 // CDC request CLEAR_UNIT_PARAMETER
descCDCRequestSetEthernetMulticastFilters = 0x40 // CDC request SET_ETHERNET_MULTICAST_FILTERS
descCDCRequestSetEthernetPowPatternFilter = 0x41 // CDC request SET_ETHERNET_POW_PATTER_FILTER
descCDCRequestGetEthernetPowPatternFilter = 0x42 // CDC request GET_ETHERNET_POW_PATTER_FILTER
descCDCRequestSetEthernetPacketFilter = 0x43 // CDC request SET_ETHERNET_PACKET_FILTER
descCDCRequestGetEthernetStatistic = 0x44 // CDC request GET_ETHERNET_STATISTIC
descCDCRequestSetATMDataFormat = 0x50 // CDC request SET_ATM_DATA_FORMAT
descCDCRequestGetATMDeviceStatistics = 0x51 // CDC request GET_ATM_DEVICE_STATISTICS
descCDCRequestSetATMDefaultVC = 0x52 // CDC request SET_ATM_DEFAULT_VC
descCDCRequestGetATMVCStatistics = 0x53 // CDC request GET_ATM_VC_STATISTICS
descCDCRequestMDLMSpecificRequestsMask = 0x7F // CDC request MDLM_SPECIFIC_REQUESTS_MASK
// Notification type
descCDCNotifyNetworkConnection = 0x00 // CDC notify NETWORK_CONNECTION
descCDCNotifyResponseAvail = 0x01 // CDC notify RESPONSE_AVAIL
descCDCNotifyAuxJackHookState = 0x08 // CDC notify AUX_JACK_HOOK_STATE
descCDCNotifyRingDetect = 0x09 // CDC notify RING_DETECT
descCDCNotifySerialState = 0x20 // CDC notify SERIAL_STATE
descCDCNotifyCallStateChange = 0x28 // CDC notify CALL_STATE_CHANGE
descCDCNotifyLineStateChange = 0x29 // CDC notify LINE_STATE_CHANGE
descCDCNotifyConnectionSpeedChange = 0x2A // CDC notify CONNECTION_SPEED_CHANGE
// Feature select
descCDCFeatureAbstractState = 0x01 // CDC feature select ABSTRACT_STATE
descCDCFeatureCountrySetting = 0x02 // CDC feature select COUNTRY_SETTING
// Control signal
descCDCControlSigBitmapCarrierActivation = 0x02 // CDC control signal CARRIER_ACTIVATION
descCDCControlSigBitmapDTEPresence = 0x01 // CDC control signal DTE_PRESENCE
// UART emulated state
descCDCUARTStateRxCarrier = 0x01 // UART state RX_CARRIER
descCDCUARTStateTxCarrier = 0x02 // UART state TX_CARRIER
descCDCUARTStateBreak = 0x04 // UART state BREAK
descCDCUARTStateRingSignal = 0x08 // UART state RING_SIGNAL
descCDCUARTStateFraming = 0x10 // UART state FRAMING
descCDCUARTStateParity = 0x20 // UART state PARITY
descCDCUARTStateOverrun = 0x40 // UART state OVERRUN
)
const (
// Size of all CDC-ACM configuration descriptors.
descCDCConfigSize = uint16(
descLengthConfigure + // Configuration Header
descLengthInterface + // CDC Interface Descriptor
descLengthInterfaceAssociation + // IAD
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
)
// descCDCLineCodingSize defines the length of a CDC-ACM UART line coding
// buffer. Note that the actual buffer may be padded for alignment; but for
// Rx/Tx transfer purposes, descCDCLineCodingSize defines the number of bytes
// that are transferred following a control SETUP request.
const descCDCLineCodingSize = 7
// descCDCLineCoding represents an emulated UART's line configuration.
//
// Use descCDCLineCodingSize instead of unsafe.Sizeof(descCDCLineCoding)
// in any transfer requests, because the actual struct is padded for alignment.
type descCDCLineCoding struct {
baud uint32
stopBits uint8
parity uint8
numBits uint8
_ uint8
}
// parse initializes the receiver descCDCLineCoding from the given []uint8 v.
// Argument v is a Rx transfer buffer, filled following the completion of a
// control transfer from a CDC SET_LINE_CODING (0x20) request
func (s *descCDCLineCoding) parse(v []uint8) bool {
if len(v) >= descCDCLineCodingSize {
s.baud = packU32(v[:])
s.stopBits = v[4]
s.parity = v[5]
s.numBits = v[6]
return true
}
return false
}
// descCDCLineState represents an emulated UART's line state.
type descCDCLineState struct {
// dataTerminalReady indicates if DTE is present or not.
// Corresponds to V.24 signal 108/2 and RS-232 signal DTR.
dataTerminalReady bool // DTR
// requestToSend is the carrier control for half-duplex modems.
// Corresponds to V.24 signal 105 and RS-232 signal RTS.
requestToSend bool // RTS
}
// parse initializes the receiver descCDCLineState from the given uint16 v.
// Argument v corresponds to the wValue field in a control SETUP packet, which
// carries the line state from a CDC SET_CONTROL_LINE_STATE (0x22) request.
func (s *descCDCLineState) parse(v uint16) bool {
s.dataTerminalReady = 0 != v&0x1
s.requestToSend = 0 != v&0x2
return true
}
// Common configuration constants for the USB CDC-ACM (single) device class.
const (
descCDCLanguageCount = 1 // String descriptor languages available
descCDCInterfaceCount = 2 // Interfaces for all CDC-ACM configurations.
descCDCEndpointCount = 4 // Endpoints for all CDC-ACM configurations.
descCDCEndpointCtrl = 0 // CDC-ACM Control Endpoint 0
descCDCInterfaceCtrl = 0 // CDC-ACM Control Interface
descCDCEndpointStatus = 1 // CDC-ACM Interrupt IN Endpoint
descCDCConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
descCDCInterfaceData = 1 // CDC-ACM Data Interface
descCDCEndpointDataRx = 2 // CDC-ACM Bulk Data OUT (Rx) Endpoint
descCDCConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
descCDCEndpointDataTx = 3 // CDC-ACM Bulk Data IN (Tx) Endpoint
descCDCConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
)
// descCDCClass holds references to all descriptors, buffers, and control
// structures for the USB CDC-ACM (single) device class.
type descCDCClass struct {
*descCDCClassData // Target-defined, class-specific data
locale *[descCDCLanguageCount]descStringLanguage // string descriptors
device *[descLengthDevice]uint8 // device descriptor
qualif *[descLengthQualification]uint8 // device qualification descriptor
config *[descCDCConfigSize]uint8 // configuration descriptor
}
// descCDC holds statically-allocated instances for each of the CDC-ACM
// (single) device class configurations, ordered by index (offset by -1).
var descCDC = [dcdCount]descCDCClass{
{ // CDC-ACM (single) class configuration index 1
descCDCClassData: &descCDCData[0],
locale: &[descCDCLanguageCount]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)
descDeviceClassCodeMisc, // Class code (assigned by the USB-IF).
descDeviceSubClassCommon, // Subclass code (assigned by the USB-IF).
descDeviceProtocolIAD, // 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
descCDCCount, // 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)
descCDCCount, // Number of possible configurations
0, // Reserved
},
config: &[descCDCConfigSize]uint8{
descLengthConfigure, // Size of this descriptor in bytes
descTypeConfigure, // Descriptor Type
lsU8(descCDCConfigSize), // Total length of data returned for this configuration (low)
msU8(descCDCConfigSize), // Total length of data returned for this configuration (high)
descCDCInterfaceCount, // 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
descCDCMaxPowerMa >> 1, // Max power consumption when fully-operational (2 mA units)
// Interface Association Descriptor
descLengthInterfaceAssociation, // Size of this descriptor in bytes
descTypeInterfaceAssociation, // Descriptor Type
0x00, // bFirstInterface
descCDCInterfaceCount, // bInterfaceCount
0x02, // bFunctionClass : Communications and CDC Control (0x02)
0x02, // bFunctionSubClass
0x00, // bFunctionProtocol
0x00, // iFunction
// Communication/Control Interface Descriptor
descLengthInterface, // Descriptor length
descTypeInterface, // Descriptor type
descCDCInterfaceCtrl, // Interface index
0, // Alternate setting
1, // Number of endpoints
descCDCTypeComm, // Class code
descCDCSubAbstractControl, // Subclass code
descCDCProtoAT250, // Protocol code (NOTE: Teensyduino & Arduino-Mbed define 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
descCDCInterfaceData, // 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
descCDCInterfaceCtrl, // Controlling interface index
descCDCInterfaceData, // Controlled interface index
// Communication/Control Notification Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCEndpointStatus | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeInterrupt, // Attributes
lsU8(descCDCStatusPacketSize), // Max packet size (low)
msU8(descCDCStatusPacketSize), // Max packet size (high)
descCDCStatusInterval, // Polling Interval
// Data Interface Descriptor
descLengthInterface, // Interface length
descTypeInterface, // Interface type
descCDCInterfaceData, // 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
descCDCEndpointDataRx | // Endpoint address
descEndptAddrDirectionOut,
descEndptTypeBulk, // Attributes
lsU8(descCDCDataRxPacketSize), // Max packet size (low)
msU8(descCDCDataRxPacketSize), // Max packet size (high)
0, // Polling Interval
// Data Bulk Tx Endpoint descriptor
descLengthEndpoint, // Size of this descriptor in bytes
descTypeEndpoint, // Descriptor Type
descCDCEndpointDataTx | // Endpoint address
descEndptAddrDirectionIn,
descEndptTypeBulk, // Attributes
lsU8(descCDCDataTxPacketSize), // Max packet size (low)
msU8(descCDCDataTxPacketSize), // Max packet size (high)
0, // Polling Interval
},
},
}
+244
View File
@@ -0,0 +1,244 @@
//go:build usb.cdc && (atsamd51 || atsame5x)
// +build usb.cdc
// +build atsamd51 atsame5x
package usb
import "runtime/volatile"
// descCDCCount defines the number of USB cores that may be configured as
// CDC-ACM (single) devices.
const descCDCCount = 1
// Constants for USB CDC-ACM device classes.
const (
// USB Bus Configuration Attributes
descCDCMaxPowerMa = 100 // Maximum current (mA) requested from host
// CDC-ACM Endpoint Descriptor Buffers
descCDCEDCount = descMaxEndpoints
// Setup packet is only 8 bytes in length. However, under certain scenarios,
// USB DMA controller may decide to overwrite/overflow the buffer with 2 extra
// bytes of CRC. From datasheet's "Management of SETUP Transactions" section:
// | If the number of received data bytes is the maximum data payload
// | specified by PCKSIZE.SIZE minus one, only the first CRC data is written
// | to the data buffer. If the number of received data is equal or less
// | than the data payload specified by PCKSIZE.SIZE minus two, both CRC
// | data bytes are written to the data buffer.
// Thus, we need to allocate 2 extra bytes for control endpoint 0 Rx (OUT).
descCDCSxSize = 8 + 2
descCDCCxSize = descControlPacketSize
// CDC-ACM Data Buffers
descCDCRxSize = descCDCDataRxPacketSize
descCDCTxSize = descCDCDataTxPacketSize
descCDCTxTimeoutMs = 120 // millisec
descCDCTxSyncUs = 75 // microsec
// Default CDC-ACM Endpoint Configurations (Full-Speed)
descCDCStatusInterval = descCDCStatusFSInterval // Status
descCDCStatusPacketSize = descCDCStatusFSPacketSize //
descCDCDataRxPacketSize = descCDCDataRxFSPacketSize // Data Rx
descCDCDataTxPacketSize = descCDCDataTxFSPacketSize // Data Tx
// CDC-ACM Endpoint Configurations for Full-Speed Device
descCDCStatusFSInterval = 5 // Status
descCDCStatusFSPacketSize = 64 // (full-speed)
descCDCDataRxFSPacketSize = 64 // Data Rx (full-speed)
descCDCDataTxFSPacketSize = 64 // Data Tx (full-speed)
// CDC-ACM Endpoint Configurations for High-Speed Device
// - N/A, SAMx51 only has a full-speed PHY
)
// descCDC0ED is an array of endpoint descriptors, which describes to the USB
// DMA controller the buffer and transfer properties for each endpoint, for the
// default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0ED [descCDCEDCount]dhwEPAddrDesc
// descCDC0Sx is the receive (Rx) buffer for setup packets on control endpoint
// 0 of the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0Sx [descCDCSxSize]uint8
// descCDC0Cx is the transmit (Tx) buffer for control/status packets on control
// endpoint 0 of the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0Cx [descCDCCxSize]uint8
// descCDC0Dx 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 descCDC0Dx [descCDCConfigSize]uint8
// descCDC0Rx is the receive (Rx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Rx [descCDCRxSize]uint8
// descCDC0Tx is the transmit (Tx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Tx [descCDCTxSize]uint8
// descCDC0Rq is the receive (Rx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Rq [descCDCRxSize]uint8
// descCDC0Tq is the transmit (Tx) transfer buffer for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0Tq [descCDCTxSize]uint8
// descCDC0LC is the emulated UART's line coding configuration for the
// default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descCDC0LC descCDCLineCoding
// descCDC0LS is the emulated UART's line state for the default CDC-ACM
// (single) device class configuration (index 1).
//go:align 32
var descCDC0LS descCDCLineState
// descCDCState defines the state of the CDC-ACM handshake initialization.
//
// Many USB hosts will send a default SET_LINE_CODING prior to SET_LINE_STATE,
// and then another SET_LINE_CODING containing the actual terminal settings.
//
// We do not want to start UART Rx/Tx transactions until after we have
// received the final SET_LINE_CODING with the intended terminal settings.
// Otherwise, the host may cancel any data transfers occurring during a change
// in line state or line coding.
//
// The "set" method on type descCDCState defines this incremental state
// machine, with the UART's current state stored in the volatile.Register8
// field "st" of descCDCClassData.
type descCDCState uint8
// set implements the state transition logic described in the godoc comment on
// type descCDCState. Returns the value of the resulting state.
//go:inline
func (s *descCDCState) set(state descCDCState) descCDCState {
if state > *s {
// state must be incremented in-order. Otherwise, reset to initial state.
if state == *s+1 {
*s = state
} else {
var init descCDCState // Reset to zero-value of type.
*s = init
}
}
// Return a value for safely chaining the result.
// (Not a pointer to the object we just modified.)
return *s
}
const (
descCDCStateConfigured descCDCState = iota // Received SET_CONFIGURATION class request
descCDCStateLineState // Received SET_LINE_STATE after Configured state
descCDCStateLineCoding // Received SET_LINE_CODING after LineState state
)
// descCDCClassData holds the buffers and control states for all CDC-ACM
// (single) device class configurations, ordered by index (offset by -1), for
// SAMx51 targets only.
//
// Instances of this type (elements of descCDCData) are embedded in elements
// of the common/target-agnostic CDC-ACM class configurations (descCDC).
// 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 descCDCClassData struct {
// CDC-ACM Control Buffers
ed *[descCDCEDCount]dhwEPAddrDesc // endpoint descriptors
sx *[descCDCSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
cx *[descCDCCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
dx *[descCDCConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
// CDC-ACM Data Buffers
rx *[descCDCRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
tx *[descCDCTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
rxq *[descCDCRxSize]uint8 // CDC-ACM UART Rx FIFO
txq *[descCDCTxSize]uint8 // CDC-ACM UART Tx FIFO
rq *Queue // CDC-ACM UART Rx Queue (backed by FIFO rxq)
tq *Queue // CDC-ACM UART Tx Queue (backed by FIFO txq)
lc *descCDCLineCoding // UART line coding
ls *descCDCLineState // UART line state
st volatile.Register8
sxSize uint32
rxSize uint32
txSize uint32
}
// setState is a wrapper for converting and storing the given descCDCState
// value as a uint8 in the receiver's volatile.Register8 field st.
//go:inline
func (c *descCDCClassData) setState(state descCDCState) {
s := descCDCState(c.st.Get())
c.st.Set(uint8(s.set(state)))
}
// state is a wrapper for retrieving and converting the receiver's
// volatile.Register8 field st from uint8 to descCDCState.
//go:inline
func (c *descCDCClassData) state() descCDCState {
return descCDCState(c.st.Get())
}
// descCDCData holds statically-allocated instances for each of the target-
// specific (SAMx51) 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 descCDC.
var descCDCData = [dcdCount]descCDCClassData{
{ // -- CDC-ACM (single) Class Configuration Index 1 --
// CDC-ACM Control Buffers
ed: &descCDC0ED,
sx: &descCDC0Sx,
cx: &descCDC0Cx,
dx: &descCDC0Dx,
// CDC-ACM Data Buffers
rx: &descCDC0Rx,
tx: &descCDC0Tx,
rxq: &descCDC0Rq,
txq: &descCDC0Tq,
rq: &Queue{},
tq: &Queue{},
lc: &descCDC0LC,
ls: &descCDC0LS,
sxSize: descCDCStatusPacketSize,
rxSize: descCDCDataRxPacketSize,
txSize: descCDCDataTxPacketSize,
},
}
+515
View File
@@ -0,0 +1,515 @@
//go:build usb.hid
// +build usb.hid
package usb
// descCDCCount defines the number of USB cores that may be configured as
// CDC-ACM (single) devices.
const descCDCCount = 0
// USB HID constants defined per specification
const (
// HID class
descHIDType = 0x03
// 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 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 Tx Endpoint Descriptor
descLengthEndpoint + // Serial Rx Endpoint Descriptor
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
)
// 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.
descHIDEndpointCtrl = 0 // HID Control Endpoint 0
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
descHIDMaxPowerMa >> 1, // 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
}
+274
View File
@@ -0,0 +1,274 @@
//go:build usb.hid && (atsamd51 || atsame5x)
// +build usb.hid
// +build atsamd51 atsame5x
package usb
// descHIDCount defines the number of USB cores that may be configured as a
// composite (keyboard + mouse + joystick) human interface device (HID).
const descHIDCount = 1
// Constants for USB HID (keyboard, mouse, joystick) device classes.
const (
// USB Bus Configuration Attributes
descHIDMaxPowerMa = 100 // Maximum current (mA) requested from host
// HID Endpoint Descriptor Buffers
descHIDEDCount = descMaxEndpoints
// Setup packet is only 8 bytes in length. However, under certain scenarios,
// USB DMA controller may decide to overwrite/overflow the buffer with 2 extra
// bytes of CRC. From datasheet's "Management of SETUP Transactions" section:
// | If the number of received data bytes is the maximum data payload
// | specified by PCKSIZE.SIZE minus one, only the first CRC data is written
// | to the data buffer. If the number of received data is equal or less
// | than the data payload specified by PCKSIZE.SIZE minus two, both CRC
// | data bytes are written to the data buffer.
// Thus, we need to allocate 2 extra bytes for control endpoint 0 Rx (OUT).
descHIDSxSize = 8 + 2
descHIDCxSize = descControlPacketSize
// HID Serial Buffers
descHIDSerialRxSize = descHIDSerialRxPacketSize
descHIDSerialTxSize = descHIDSerialTxPacketSize
descHIDSerialTxTimeoutMs = 50 // millisec
descHIDSerialTxSyncUs = 75 // microsec
// HID Keyboard Buffers
descHIDKeyboardTxSize = 4 * descHIDKeyboardTxPacketSize
descHIDKeyboardTxTimeoutMs = 50 // millisec
// HID Mouse Buffers
descHIDMouseTxSize = 4 * descHIDMouseTxPacketSize
descHIDMouseTxTimeoutMs = 30 // millisec
// HID Joystick Buffers
descHIDJoystickTxSize = 4 * descHIDJoystickTxPacketSize
descHIDJoystickTxTimeoutMs = 30 // millisec
// Default HID Endpoint Configurations (Full-Speed)
descHIDSerialRxInterval = descHIDSerialRxFSInterval // Serial Rx
descHIDSerialRxPacketSize = descHIDSerialRxFSPacketSize //
descHIDSerialTxInterval = descHIDSerialTxFSInterval // Serial Tx
descHIDSerialTxPacketSize = descHIDSerialTxFSPacketSize //
descHIDKeyboardTxInterval = descHIDKeyboardTxFSInterval // Keyboard
descHIDKeyboardTxPacketSize = descHIDKeyboardTxFSPacketSize //
descHIDMediaKeyTxInterval = descHIDMediaKeyTxFSInterval // Keyboard Media Keys
descHIDMediaKeyTxPacketSize = descHIDMediaKeyTxFSPacketSize //
descHIDMouseTxInterval = descHIDMouseTxFSInterval // Mouse
descHIDMouseTxPacketSize = descHIDMouseTxFSPacketSize //
descHIDJoystickTxInterval = descHIDJoystickTxFSInterval // Joystick
descHIDJoystickTxPacketSize = descHIDJoystickTxFSPacketSize //
// 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
// - N/A, SAMx51 only has a full-speed PHY
)
// descHID0ED is an array of endpoint descriptors, which describes to the USB
// DMA controller the buffer and transfer properties for each endpoint, for the
// default HID device class configuration (index 1).
//go:align 32
var descHID0ED [descHIDEDCount]dhwEPAddrDesc
// descHID0Sx is the receive (Rx) buffer for setup packets on control endpoint 0
// of the default HID device class configuration (index 1).
//go:align 32
var descHID0Sx [descHIDSxSize]uint8
// descHID0Cx is the transmit (Tx) buffer for control/status packets on control
// endpoint 0 of the default CDC-ACM (single) device class configuration (index 1).
//go:align 32
var descHID0Cx [descHIDCxSize]uint8
// 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
// descHID0SerialRx is the serial receive (Rx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
// var descHID0SerialRx [descHIDSerialRxSize]uint8
// descHID0SerialTx is the serial transmit (Tx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
// var descHID0SerialTx [descHIDSerialTxSize]uint8
// descHID0KeyboardTx is the keyboard HID report transmit (Tx) transfer buffer
// for the default HID device class configuration (index 1).
//go:align 32
var descHID0KeyboardTx [descHIDKeyboardTxPacketSize]uint8
// descHID0KeyboardTq is the keyboard transmit (Tx) transfer buffer for the
// default HID device class configuration (index 1).
//go:align 32
// var descHID0KeyboardTq [descHIDKeyboardTxSize]uint8
// descHID0MouseTx is the mouse transmit (Tx) transfer buffer for the default
// HID device class configuration (index 1).
//go:align 32
// var descHID0MouseTx [descHIDMouseTxSize]uint8
// descHID0JoystickTx is the joystick transmit (Tx) transfer buffer for the
// default HID device class configuration (index 1).
//go:align 32
// var descHID0JoystickTx [descHIDJoystickTxSize]uint8
var descHID0KeyboardTxKey [hidKeyboardKeyCount]uint8
var descHID0KeyboardTxCon [hidKeyboardConCount]uint16
var descHID0KeyboardTxSys [hidKeyboardSysCount]uint8
// descHID0Keyboard is the Keyboard instance with which the user may interact
// when using the default HID device class configuration (index 1).
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 SAMx51
// 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
ed *[descHIDEDCount]dhwEPAddrDesc // endpoint descriptors
sx *[descHIDSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
cx *[descHIDCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
dx *[descHIDConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
// HID Serial Buffers
// rxSerial *[descHIDSerialRxSize]uint8 // interrupt endpoint serial Rx (OUT) transfer buffer
// txSerial *[descHIDSerialTxSize]uint8 // interrupt endpoint serial Tx (IN) transfer buffer
// rxSerialSize uint16
// txSerialSize uint16
// HID Keyboard Buffers
txKeyboard *[descHIDKeyboardTxPacketSize]uint8 // interrupt endpoint keyboard Tx (IN) HID report buffer
// txqKeyboard *[descHIDKeyboardTxSize]uint8 // interrupt endpoint keyboard Tx (IN) transfer FIFO
// tqKeyboard *Queue
txKeyboardSize uint16
// HID Mouse Buffers
// txMouse *[descHIDMouseTxSize]uint8 // interrupt endpoint mouse Tx (IN) transfer buffer
// txMouseSize uint16
// HID Joystick Buffers
// txJoystick *[descHIDJoystickTxSize]uint8 // interrupt endpoint joystick Tx (IN) transfer buffer
// txJoystickSize uint16
// HID Device Instances
//serial *Serial
keyboard *Keyboard
//mouse *Mouse
//joystick *Joystick
}
// descHIDData holds statically-allocated instances for each of the target-
// specific (SAMx51) 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.
var descHIDData = [dcdCount]descHIDClassData{
{ // -- HID Class Configuration Index 1 --
// HID Control Buffers
ed: &descHID0ED,
sx: &descHID0Sx,
cx: &descHID0Cx,
dx: &descHID0Dx,
// HID Serial Buffers
// rxSerial: &descHID0SerialRx,
// txSerial: &descHID0SerialTx,
// rxSerialSize: descHIDSerialRxPacketSize,
// txSerialSize: descHIDSerialTxPacketSize,
// HID Keyboard Buffers
txKeyboard: &descHID0KeyboardTx,
// txqKeyboard: &descHID0KeyboardTq,
// tqKeyboard: &Queue{},
txKeyboardSize: descHIDKeyboardTxPacketSize,
// HID Mouse Buffers
// txMouse: &descHID0MouseTx,
// txMouseSize: descHIDMouseTxPacketSize,
// HID Joystick Buffers
// txJoystick: &descHID0JoystickTx,
// txJoystickSize: descHIDJoystickTxPacketSize,
// HID Device Instances
//serial: &descHID0Serial,
keyboard: &descHID0Keyboard,
//mouse: &descHID0Mouse,
//joystick: &descHID0Joystick,
},
}
+221
View File
@@ -0,0 +1,221 @@
package usb
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
const descLanguageEnglish = uint16(0x0409) // (US) English
// USB constants defined per specification.
const (
// Descriptor length
descLengthDevice = 18
descLengthConfigure = 9
descLengthInterface = 9
descLengthInterfaceAssociation = 8
descLengthEndpoint = 7
descLengthQualification = 10
descLengthOTG = 5
descLengthBOS = 5
descLengthEndpointCompanion = 6
descLengthUSB20Extension = 7
descLengthSuperspeed = 10
// Descriptor type
descTypeDevice = 0x01
descTypeConfigure = 0x02
descTypeString = 0x03
descTypeInterface = 0x04
descTypeEndpoint = 0x05
descTypeQualification = 0x06
descTypeOtherSpeedConfiguration = 0x07
descTypeInterfacePower = 0x08
descTypeOTG = 0x09
descTypeInterfaceAssociation = 0x0B
descTypeBOS = 0x0F
descTypeDeviceCapability = 0x10
descTypeHID = 0x21
descTypeHIDReport = 0x22
descTypeHIDPhysical = 0x23
descTypeCDCInterface = 0x24
descTypeCDCEndpoint = 0x25
descTypeEndpointCompanion = 0x30
// Standard request type
descRequestTypeDirMsk = 0x80
descRequestTypeDirPos = 7
descRequestTypeDirOut = 0x00
descRequestTypeDirIn = 0x80
descRequestTypeTypeMsk = 0x60
descRequestTypeTypePos = 5
descRequestTypeTypeStandard = 0
descRequestTypeTypeClass = 0x20
descRequestTypeTypeVendor = 0x40
descRequestTypeRecipientMsk = 0x1F
descRequestTypeRecipientPos = 0
descRequestTypeRecipientDevice = 0x00
descRequestTypeRecipientInterface = 0x01
descRequestTypeRecipientEndpoint = 0x02
descRequestTypeRecipientOther = 0x03
// Standard request
descRequestStandardGetStatus = 0x00
descRequestStandardClearFeature = 0x01
descRequestStandardSetFeature = 0x03
descRequestStandardSetAddress = 0x05
descRequestStandardGetDescriptor = 0x06
descRequestStandardSetDescriptor = 0x07
descRequestStandardGetConfiguration = 0x08
descRequestStandardSetConfiguration = 0x09
descRequestStandardGetInterface = 0x0A
descRequestStandardSetInterface = 0x0B
descRequestStandardSynchFrame = 0x0C
// Configuration attributes
descConfigAttrD7Msk = 0x80
descConfigAttrD7Pos = 7
descConfigAttrSelfPoweredMsk = 0x40
descConfigAttrSelfPoweredPos = 6
descConfigAttrRemoteWakeupMsk = 0x20
descConfigAttrRemoteWakeupPos = 5
// Endpoint type
descEndptTypeControl = 0x00
descEndptTypeIsochronous = 0x01
descEndptTypeBulk = 0x02
descEndptTypeInterrupt = 0x03
// Endpoint address
descEndptAddrNumberMsk = 0x0F
descEndptAddrNumberPos = 0
descEndptAddrDirectionMsk = 0x80
descEndptAddrDirectionPos = 7
descEndptAddrDirectionOut = 0
descEndptAddrDirectionIn = 0x80
// Endpoint attributes
descEndptAttrTypeMsk = 0x03
descEndptAttrNumberPos = 0
descEndptAttrSyncTypeMsk = 0x0C
descEndptAttrSyncTypePos = 2
descEndptAttrSyncTypeNoSync = 0x00
descEndptAttrSyncTypeAsync = 0x04
descEndptAttrSyncTypeAdaptive = 0x08
descEndptAttrSyncTypeSync = 0x0C
descEndptAttrUsageTypeMsk = 0x30
descEndptAttrUsageTypePos = 4
descEndptAttrUsageTypeData = 0x00
descEndptAttrUsageTypeFeed = 0x10
descEndptAttrUsageTypeFeedData = 0x20
// Endpoint max packet size
descEndptMaxPktSizeMsk = 0x07FF
descEndptMaxPktSize = 64
descEndptMaxPktSizeMultMsk = 0x1800
descEndptMaxPktSizeMultPos = 11
// OTG attributes
descOTGAttrSRPMsk = 0x01
descOTGAttrHNPMsk = 0x02
descOTGAttrADPMsk = 0x04
// Device bus speed
descDeviceSpeedFull = 0x00
descDeviceSpeedLow = 0x01
descDeviceSpeedHigh = 0x02
descDeviceSpeedSuper = 0x04
// Device capability type
descDeviceCapTypeWireless = 0x01
descDeviceCapTypeUSB20Extension = 0x02
descDeviceCapTypeSuperspeed = 0x03
// Device capability attributes (USB 2.0 extension)
descDeviceCapExtAttrLPMMsk = 0x02
descDeviceCapExtAttrLPMPos = 1
descDeviceCapExtAttrBESLMsk = 0x04
descDeviceCapExtAttrBESLPos = 2
// Device class
descDeviceClassCodeMisc = 0xEF
descDeviceSubClassCommon = 0x02
descDeviceProtocolIAD = 0x01
)
// descEndpointInvalid represents an invalid endpoint address.
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
const (
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
descDirRx = descDirOut // "IN" and "OUT" terms are from host's perspective,
descDirTx = descDirIn // which is opposite from USB device. Kinda awkward.
)
// device returns the enumerated device descriptor value, defined per USB
// specification, for the receiver Speed s.
func (s Speed) device() uint32 {
switch s {
case LowSpeed:
return descDeviceSpeedLow
case FullSpeed:
return descDeviceSpeedFull
case HighSpeed:
return descDeviceSpeedHigh
case SuperSpeed, DualSuperSpeed:
return descDeviceSpeedSuper
default: // unrecognized Speed defaults to full-speed
return descDeviceSpeedFull
}
}
const (
// Common attributes for all endpoint descriptor configurations.
descEndptConfigAttr = descConfigAttrD7Msk | // Bit 7: reserved (1)
(0 << descConfigAttrSelfPoweredPos) | // Bit 6: self-powered
(0 << descConfigAttrRemoteWakeupPos) | // Bit 5: remote wakeup
0 // Bits 0-4: reserved (0)
descEndptConfigAttrRxPos = 0
descEndptConfigAttrTxPos = 16
descEndptConfigAttrRxMsk = (descEndptAttrSyncTypeMsk | descEndptConfigAttr) << descEndptConfigAttrRxPos
descEndptConfigAttrTxMsk = (descEndptAttrSyncTypeMsk | descEndptConfigAttr) << descEndptConfigAttrTxPos
descEndptConfigAttrRxUnused = 0x02 << descEndptConfigAttrRxPos
descEndptConfigAttrTxUnused = 0x02 << descEndptConfigAttrTxPos
descEndptConfigAttrRxIsochronous = (descEndptAttrSyncTypeAsync | descEndptConfigAttr) << descEndptConfigAttrRxPos
descEndptConfigAttrTxIsochronous = (descEndptAttrSyncTypeAsync | descEndptConfigAttr) << descEndptConfigAttrTxPos
descEndptConfigAttrRxBulk = (descEndptAttrSyncTypeAdaptive | descEndptConfigAttr) << descEndptConfigAttrRxPos
descEndptConfigAttrTxBulk = (descEndptAttrSyncTypeAdaptive | descEndptConfigAttr) << descEndptConfigAttrTxPos
descEndptConfigAttrRxInterrupt = (descEndptAttrSyncTypeSync | descEndptConfigAttr) << descEndptConfigAttrRxPos
descEndptConfigAttrTxInterrupt = (descEndptAttrSyncTypeSync | descEndptConfigAttr) << descEndptConfigAttrTxPos
)
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
// remaining bytes are UTF-16 code points, ordered low byte-first. If you just
// want to use UTF-8 (or even ASCII), you still need to reserve 2 bytes for
// each symbol, but you can set all of their high bytes 0.
descString [descStringSize]uint8
// descStringIndex defines an indexed collection of string descriptors for a
// given language.
descStringIndex [descStringIndexCount]descString
// descStringLanguage contains a language code and an indexed collection of
// string descriptors encoded in that language.
descStringLanguage struct {
language uint16
descriptor descStringIndex
}
)
const (
descStringIndexCount = 4 // Language, Manufacturer, Product, Serial Number
descStringSize = 64 // (64-2)/2 = 31 chars each (UTF-16 code points)
// The maximum allowable string descriptor size is 255, or (255-2)/2 = 126
// available UTF-16 code points. Considering we are allocating this storage at
// compile-time, it seems like an awful waste of space (255*4 = ~1 KiB) just
// to store four strings, which, in all likelihood, will not be modified by
// anyone other than TinyGo devs; 64*4 = 256 B (i.e., 31 UTF-16 code points
// for each string) seems a good compromise.
)
+34
View File
@@ -0,0 +1,34 @@
//go:build atsamd51 || atsame5x
// +build atsamd51 atsame5x
package usb
// descCPUFrequencyHz defines the target CPU frequency (Hz).
const descCPUFrequencyHz = 120000000
// descCoreCount defines the number of USB PHY cores available on this platform,
// independent of the number of cores which shall be configured as TinyGo USB
// host/device controller instances.
const descCoreCount = 1 // SAMx51 has a single, full-speed USB PHY
// General USB device identification constants.
const (
descCommonVendorID = 0x03EB
descCommonProductID = 0x2421
descCommonReleaseID = 0x0101 // BCD (1.1)
descCommonLanguage = descLanguageEnglish
descCommonManufacturer = "TinyGo"
descCommonProduct = "USB"
descCommonSerialNumber = "00000"
)
// Constants for all USB device classes.
const (
// USB endpoints parameters
descMaxEndpoints = 8 // SAMx51 maximum number of endpoints
descControlPacketSize = 64
)
+622
View File
@@ -0,0 +1,622 @@
//go:build mimxrt1062
// +build mimxrt1062
package usb
// descCPUFrequencyHz defines the target CPU frequency (Hz).
const descCPUFrequencyHz = 600000000
// descCoreCount defines the number of USB PHY cores available on this platform,
// independent of the number of cores which shall be configured as TinyGo USB
// host/device controller instances.
const descCoreCount = 2
// descCDCACMCount defines the number of USB cores that may be configured as
// CDC-ACM (single) devices.
const descCDCACMCount = 1
// descHIDCount defines the number of USB cores that may be configured as a
// composite (keyboard + mouse + joystick) human interface device (HID).
const descHIDCount = 0
// General USB device identification constants.
const (
descCommonVendorID = 0x16C0
descCommonProductID = 0x0483
descCommonReleaseID = 0x0101 // BCD (1.1)
descCommonLanguage = descLanguageEnglish
descCommonManufacturer = "TinyGo"
descCommonProduct = "USB"
descCommonSerialNumber = "00000"
)
// Constants for USB CDC-ACM device classes.
const (
// USB bus configuration attributes
descCDCACMMaxPowerMa = 100 // Maximum current (mA) requested from host
// CDC-ACM Control Buffers
descCDCACMQHCount = 2 * (descCDCACMEndpointCount + 1)
descCDCACMCxCount = 8
// 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
// Default CDC-ACM Endpoint Configurations (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 (
// USB bus configuration attributes
descHIDMaxPowerMa = 100 // Maximum current (mA) requested from host
// 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
// transfers for a given endpoint are managed, for the default CDC-ACM (single)
// device class configuration (index 1).
//
// From the iMXRT1062 Reference Manual:
//
// Software must ensure that no interface data structure reachable
// by the Device Controller spans a 4K-page boundary.
//
// The [queue head] is a 48-byte data structure, but must be aligned on
// 64-byte boundaries.
//
// Endpoint queue heads are arranged in an array in a continuous area of
// memory pointed to by the USB.ENDPOINTLISTADDR pointer. The even-numbered
// device queue heads in the list support receive endpoints (OUT/SETUP) and
// the odd-numbered queue heads in the list are used for transmit endpoints
// (IN/INTERRUPT). The device controller will index into this array based upon
// the endpoint number received from the USB bus. All information necessary to
// respond to transactions for all primed transfers is contained in this list
// so the Device Controller can readily respond to incoming requests without
// having to traverse a linked list.
//go:align 4096
var descCDCACM0QH [descCDCACMQHCount]dhwEndpoint
// 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
// class configuration (index 1).
//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)
// device class configuration (index 1).
//go:align 32
var descCDCACM0TD [descCDCACMTDCount]dhwTransfer
// 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
var descCDCACM0RDNum [descCDCACMRDCount]uint16
var descCDCACM0RDIdx [descCDCACMRDCount]uint16
var descCDCACM0RDQue [(descCDCACMRDCount + 1)]uint16
// 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.
//
// Instances of this type (elements of descCDCACMData) are embedded in elements
// 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 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 transfer descriptor
cx *[descCDCACMCxCount]uint8 // control endpoint 0 Rx/Tx transfer buffer
ad *dhwTransfer // control endpoint 0 Rx/Tx ACK transfer descriptor
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
// 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
txHead uint8
txFree uint16
txPrev bool
rxHead uint8
rxTail uint8
rxFree uint16
}
// 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 64
var descCDCACMData = [dcdCount]descCDCACMClassData{
{ // -- CDC-ACM (single) Class Configuration Index 1 --
// CDC-ACM Control Buffers
qh: &descCDCACM0QH,
cd: &descCDCACM0CD,
cx: &descCDCACM0Cx,
ad: &descCDCACM0AD,
dx: &descCDCACM0Dx,
// 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
//serial *Serial
keyboard *Keyboard
//mouse *Mouse
//joystick *Joystick
}
// 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
//serial: &descHID0Serial,
keyboard: &descHID0Keyboard,
//mouse: &descHID0Mouse,
//joystick: &descHID0Joystick,
},
}
+243
View File
@@ -0,0 +1,243 @@
//go:build usb.cdc && (atsamd51 || atsame5x)
// +build usb.cdc
// +build atsamd51 atsame5x
package usb
import "unsafe"
//go:inline
func (d *dhw) descriptorTable() uintptr {
return uintptr(unsafe.Pointer(&descCDC[d.cc.config-1].ed[0]))
}
// endpointDescriptor returns the endpoint descriptor for the given endpoint
// address, encoded as direction D and endpoint number N with the 8-bit mask
// D000NNNN.
//go:inline
func (d *dhw) endpointDescriptor(endpoint uint8) *dhwEPDesc {
num, dir := unpackEndpoint(endpoint)
return &descCDC[d.cc.config-1].ed[num][dir]
}
//go:inline
func (d *dhw) controlSetupBuffer() uintptr {
return uintptr(unsafe.Pointer(&descCDC[d.cc.config-1].sx[0]))
}
//go:inline
func (d *dhw) controlStatusBuffer(data []uint8) uintptr {
// reference to class configuration data
c := descCDC[d.cc.config-1]
for i := range c.cx {
c.cx[i] = 0 // zero out the control reply buffer
}
// copy the given data into control reply buffer
copy(c.cx[:], data)
return uintptr(unsafe.Pointer(&c.cx[0]))
}
// =============================================================================
// [CDC-ACM] Serial UART (Virtual COM Port)
// =============================================================================
func (d *dhw) cdcConfigure() {
acm := &descCDC[d.cc.config-1]
acm.setState(descCDCStateConfigured)
// SAMx51 only supports USB full-speed (FS) operation
acm.sxSize = descCDCStatusFSPacketSize
acm.rxSize = descCDCDataRxFSPacketSize
acm.txSize = descCDCDataTxFSPacketSize
rq := acm.rxq[:]
tq := acm.txq[:]
// Rx gives priority to incoming data, Tx gives priority to outgoing data
acm.rq.Init(&rq, int(acm.rxSize), QueueFullDiscardFirst)
acm.tq.Init(&tq, int(acm.txSize), QueueFullDiscardLast)
d.endpointEnable(txEndpoint(descCDCEndpointStatus),
false, descCDCConfigAttrStatus)
d.endpointEnable(rxEndpoint(descCDCEndpointDataRx),
false, descCDCConfigAttrDataRx)
d.endpointEnable(txEndpoint(descCDCEndpointDataTx),
false, descCDCConfigAttrDataTx)
d.endpointConfigure(txEndpoint(descCDCEndpointStatus),
nil)
d.endpointConfigure(rxEndpoint(descCDCEndpointDataRx),
d.cdcReceiveComplete)
d.endpointConfigure(txEndpoint(descCDCEndpointDataTx),
d.cdcTransmitComplete)
d.cdcReceiveStart(rxEndpoint(descCDCEndpointDataRx))
}
func (d *dhw) cdcSetLineState(state uint16) {
acm := &descCDC[d.cc.config-1]
acm.setState(descCDCStateLineState)
if acm.ls.parse(state) {
// TBD: respond to changes in line state?
}
}
func (d *dhw) cdcSetLineCoding(coding []uint8) {
acm := &descCDC[d.cc.config-1]
acm.setState(descCDCStateLineCoding)
if acm.lc.parse(coding) {
switch acm.lc.baud {
case 1200:
if acm.ls.dataTerminalReady {
// reboot CPU
}
}
}
}
func (d *dhw) cdcReady() bool {
acm := &descCDC[d.cc.config-1]
// Ensure we have received SET_CONFIGURATION class request, and then both
// SET_LINE_STATE and SET_LINE_CODING CDC requests (in that order).
return d.state() == dcdStateConfigured &&
acm.st.Get() == uint8(descCDCStateLineCoding)
}
func (d *dhw) cdcReceiveStart(endpoint uint8) {
acm := &descCDC[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
ready, _ := d.ep[num][descDirRx].scheduleTransfer(
uintptr(unsafe.Pointer(&acm.rx[0])), acm.rxSize)
if ready {
if xfer, ok := d.ep[num][descDirRx].pendingTransfer(); ok {
// Update the active transfer descriptor on the corresponding endpoint.
d.ep[num][descDirRx].setActiveTransfer(xfer)
d.endpointTransfer(endpoint, xfer.data, xfer.size)
}
}
}
func (d *dhw) cdcReceiveComplete(endpoint uint8, size uint32) {
acm := &descCDC[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
if xfer, ok := d.ep[num][descDirRx].activeTransfer(); ok {
for ptr := xfer.data; ptr < xfer.data+uintptr(size); ptr++ {
acm.rq.Enq(*(*uint8)(unsafe.Pointer(ptr)))
}
}
d.ep[num][descDirRx].setActiveTransfer(nil)
d.cdcReceiveStart(endpoint)
}
func (d *dhw) cdcTransmitStart(endpoint uint8) {
acm := &descCDC[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
// BULK data endpoints can simply use a single time slot in the schedule, and
// repeatedly transfer from the same transmit buffer (acm.tx) as soon as the
// transaction complete callback has been called for a prior transaction.
// Do not schedule another transfer if one is already active, or if our Tx
// FIFO is currently empty.
if d.ep[num][descDirTx].hasActiveTransfer() || acm.tq.Len() == 0 {
return
}
if send, err := acm.tq.Read(acm.tx[:]); err == nil && send > 0 {
ready, _ := d.ep[num][descDirTx].scheduleTransfer(
uintptr(unsafe.Pointer(&acm.tx[0])), uint32(send))
if ready {
if xfer, ok := d.ep[num][descDirTx].pendingTransfer(); ok {
d.ep[num][descDirTx].setActiveTransfer(xfer)
d.endpointTransfer(endpoint, xfer.data, xfer.size)
}
}
}
}
func (d *dhw) cdcTransmitComplete(endpoint uint8, size uint32) {
acm := &descCDC[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
if size > 0 && size%acm.txSize == 0 {
// Send ZLP if transfer length is a non-zero multiple of max packet size.
d.endpointTransfer(endpoint, 0, 0)
}
d.ep[num][descDirTx].setActiveTransfer(nil)
d.cdcTransmitStart(endpoint)
}
// cdcFlush discards all buffered input (Rx) data.
func (d *dhw) cdcFlush() {
acm := &descCDC[d.cc.config-1]
acm.rq.Reset(int(acm.rxSize))
}
func (d *dhw) cdcAvailable() int {
acm := &descCDC[d.cc.config-1]
return acm.rq.Len()
}
func (d *dhw) cdcPeek() (uint8, bool) {
acm := &descCDC[d.cc.config-1]
return acm.rq.Front()
}
func (d *dhw) cdcReadByte() (uint8, bool) {
acm := &descCDC[d.cc.config-1]
return acm.rq.Deq()
}
func (d *dhw) cdcRead(data []uint8) (int, error) {
acm := &descCDC[d.cc.config-1]
return acm.rq.Read(data)
}
func (d *dhw) cdcWriteByte(c uint8) error {
_, err := d.cdcWrite([]uint8{c})
return err
}
func (d *dhw) cdcWrite(data []uint8) (int, error) {
acm := &descCDC[d.cc.config-1]
num := uint16(descCDCEndpointDataTx) & descEndptAddrNumberMsk
var sent int
var werr error
for off := 0; off < len(data); off += int(acm.txSize) {
cnt := len(data[off:])
if cnt > int(acm.txSize) {
cnt = int(acm.txSize)
}
// Block until we have room in the Tx FIFO. Space will become available once
// the endpoint transaction complete interrupt is raised for the Tx BULK data
// endpoint, and then the uartTransmitComplete callback has dequeued data from
// the Tx FIFO (acm.tq) into the Tx transmit buffer (acm.tx).
for acm.tq.Rem() < cnt {
}
// Add data to Tx FIFO
add, err := acm.tq.Write(data[off : off+cnt])
if err != nil {
werr = err
break
}
sent += add
if d.ep[num][descDirTx].hasActiveTransfer() {
// If there is already a transmit in-progress, wait for its callback to
// detect new data in the FIFO and continue the transfer automatically.
} else {
// Otherwise, initiate a new data transfer.
d.cdcTransmitStart(txEndpoint(descCDCEndpointDataTx))
}
}
return sent, werr
}
+265
View File
@@ -0,0 +1,265 @@
//go:build usb.hid && (atsamd51 || atsame5x)
// +build usb.hid
// +build atsamd51 atsame5x
package usb
import "unsafe"
//go:inline
func (d *dhw) descriptorTable() uintptr {
return uintptr(unsafe.Pointer(&descHID[d.cc.config-1].ed[0]))
}
// endpointDescriptor returns the endpoint descriptor for the given endpoint
// address, encoded as direction D and endpoint number N with the 8-bit mask
// D000NNNN.
//go:inline
func (d *dhw) endpointDescriptor(endpoint uint8) *dhwEPDesc {
num, dir := unpackEndpoint(endpoint)
return &descHID[d.cc.config-1].ed[num][dir]
}
//go:inline
func (d *dhw) controlSetupBuffer() uintptr {
return uintptr(unsafe.Pointer(&descHID[d.cc.config-1].sx[0]))
}
//go:inline
func (d *dhw) controlStatusBuffer(data []uint8) uintptr {
// reference to class configuration data
c := descHID[d.cc.config-1]
for i := range c.cx {
c.cx[i] = 0 // zero out the control reply buffer
}
// copy the given data into control reply buffer
copy(c.cx[:], data)
return uintptr(unsafe.Pointer(&c.cx[0]))
}
// =============================================================================
// [HID] Serial
// =============================================================================
func (d *dhw) serialConfigure() {
// hid := &descHID[d.cc.config-1]
// SAMx51 only supports USB full-speed (FS) operation
// 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
_, _ = hid, num // TODO(ardnew): elaborate stub
}
func (d *dhw) serialTransmit() {
hid := &descHID[d.cc.config-1]
_ = hid // TODO(ardnew): elaborate stub
}
func (d *dhw) serialNotify( /* transfer *dhwTransfer */ ) {
// hid := &descHID[d.cc.config-1]
// len := hid.rxSerialSize - (uint16(transfer.token>>16) & 0x7FFF)
// _ = len // TODO(ardnew): elaborate stub
}
// serialFlush discards all buffered input (Rx) data.
func (d *dhw) serialFlush() {
hid := &descHID[d.cc.config-1]
_ = hid
}
func (d *dhw) serialSync() {
}
// =============================================================================
// [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)
// SAMx51 only supports USB full-speed (FS) operation
hid.txKeyboardSize = descHIDKeyboardTxPacketSize
// tq := hid.txqKeyboard[:]
// hid.tqKeyboard.Init(&tq, len(hid.txqKeyboard), QueueFullDiscardFirst)
d.endpointEnable(txEndpoint(descHIDEndpointKeyboard),
false, descHIDConfigAttrKeyboard)
d.endpointEnable(txEndpoint(descHIDEndpointMediaKey),
false, descHIDConfigAttrMediaKey)
d.endpointConfigure(txEndpoint(descHIDEndpointKeyboard),
d.keyboardWriteComplete)
d.endpointConfigure(txEndpoint(descHIDEndpointMediaKey),
d.keyboardWriteComplete)
}
func (d *dhw) keyboardSendKeys(consumer bool) bool {
hid := &descHID[d.cc.config-1]
data := [8]uint8{}
if !consumer {
data[0] = hid.keyboard.mod
data[1] = 0
data[2] = hid.keyboard.key[0]
data[3] = hid.keyboard.key[1]
data[4] = hid.keyboard.key[2]
data[5] = hid.keyboard.key[3]
data[6] = hid.keyboard.key[4]
data[7] = hid.keyboard.key[5]
return d.keyboardWrite(txEndpoint(descHIDEndpointKeyboard), data[:])
} else {
// 44444444 44333333 33332222 22222211 11111111 [ word ]
// 98765432 10987654 32109876 54321098 76543210 [ index ] (right-to-left)
data[1] = uint8((hid.keyboard.con[1] << 2) | ((hid.keyboard.con[0] >> 8) & 0x03))
data[2] = uint8((hid.keyboard.con[2] << 4) | ((hid.keyboard.con[1] >> 6) & 0x0F))
data[3] = uint8((hid.keyboard.con[3] << 6) | ((hid.keyboard.con[2] >> 4) & 0x3F))
data[4] = uint8(hid.keyboard.con[3] >> 2)
data[5] = hid.keyboard.sys[0]
data[6] = hid.keyboard.sys[1]
data[7] = hid.keyboard.sys[2]
return d.keyboardWrite(txEndpoint(descHIDEndpointMediaKey), data[:])
}
}
func (d *dhw) keyboardWriteComplete(endpoint uint8, size uint32) {
hid := &descHID[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
if size > 0 && size%uint32(hid.txKeyboardSize) == 0 {
// Send ZLP if transfer length is a non-zero multiple of max packet size.
d.endpointTransfer(endpoint, 0, 0)
}
d.ep[num][descDirTx].setActiveTransfer(nil)
}
func (d *dhw) keyboardWrite(endpoint uint8, data []uint8) bool {
hid := &descHID[d.cc.config-1]
num := uint16(endpoint) & descEndptAddrNumberMsk
for off := 0; off < len(data); off += int(hid.txKeyboardSize) {
cnt := len(data[off:])
if cnt > int(hid.txKeyboardSize) {
cnt = int(hid.txKeyboardSize)
}
for d.ep[num][descDirTx].hasActiveTransfer() {
}
ready, _ := d.ep[num][descDirTx].scheduleTransfer(
uintptr(unsafe.Pointer(&data[0])), uint32(cnt))
if ready {
if xfer, ok := d.ep[num][descDirTx].pendingTransfer(); ok {
d.ep[num][descDirTx].setActiveTransfer(xfer)
d.endpointTransfer(endpoint, xfer.data, xfer.size)
}
}
}
// 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]
// SAMx51 only supports USB full-speed (FS) operation
// 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]
// SAMx51 only supports USB full-speed (FS) operation
// hid.txJoystickSize = descHIDJoystickTxFSPacketSize
d.endpointEnable(descHIDEndpointJoystick,
false, descHIDConfigAttrJoystick)
// d.endpointConfigureTx(descHIDEndpointJoystick,
// hid.txJoystickSize, false, nil)
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
package usb
// Implementation of target-agnostic USB host controller driver (hcd).
// hcdCount defines the number of USB cores to configure for host mode. It is
// computed as the sum of all declared host configuration descriptors.
const hcdCount = 0 // + ...
// hcdInstance provides statically-allocated instances of each USB host
// controller configured on this platform.
var hcdInstance [hcdCount]hcd
// hhwInstance provides statically-allocated instances of each USB hardware
// abstraction for ports configured as host on this platform.
var hhwInstance [hcdCount]hhw
// hcd implements a generic USB host controller driver (hcd) for all targets.
type hcd struct {
*hhw // USB hardware abstraction layer
core *core // Parent USB core this instance is attached to
port int // USB port index
cc class // USB host class
id int // USB host controller index
}
// initHCD initializes and assigns a free host controller instance to the given
// USB port. Returns the initialized host controller or nil if no free host
// controller instances remain.
func initHCD(port int, speed Speed, class class) (*hcd, status) {
if 0 == hcdCount {
return nil, statusInvalid // Must have defined host controllers
}
switch class.id {
default:
}
// Return the first instance whose assigned core is currently nil.
for i := range hcdInstance {
if nil == hcdInstance[i].core {
// Initialize host controller.
hcdInstance[i].hhw = allocHHW(port, i, speed, &hcdInstance[i])
hcdInstance[i].core = &coreInstance[port]
hcdInstance[i].port = port
hcdInstance[i].cc = class
hcdInstance[i].id = i
return &hcdInstance[i], statusOK
}
}
return nil, statusBusy // No free host controller instances available.
}
// class returns the receiver's current host class configuration.
func (h *hcd) class() class { return h.cc }
+61
View File
@@ -0,0 +1,61 @@
//go:build atsamd51 || atsame5x
// +build atsamd51 atsame5x
package usb
// Implementation of USB host controller driver (hcd) for Microchip SAMD51.
import (
"device/sam"
"runtime/interrupt"
)
// hhwInterruptPriority defines the priority for all USB host interrupts.
const hhwInterruptPriority = 3
// hhw implements USB host controller hardware abstraction interface.
type hhw struct {
*hcd // USB host controller driver
bus *sam.USB_HOST_Type // USB core registers
irq interrupt.Interrupt // USB IRQ, only a single interrupt on SAMx51
speed Speed
}
// allocHHW returns a reference to the USB hardware abstraction for the given
// host controller driver. Should be called only one time and during host
// controller initialization.
func allocHHW(port, instance int, speed Speed, hc *hcd) *hhw {
switch port {
case 0:
hhwInstance[instance].hcd = hc
hhwInstance[instance].bus = sam.USB_HOST
}
// Port defaults to full-speed (12 Mbit/sec) on SAMx51
if 0 == speed {
speed = HighSpeed
}
hhwInstance[instance].speed = speed
return &hhwInstance[instance]
}
// init configures the USB port for host mode operation by initializing all
// endpoint and transfer descriptor data structures, initializing core registers
// and interrupts, resetting the USB PHY, and enabling power on the bus.
func (h *hhw) init() status {
return statusOK
}
// enable causes the USB core to enter (or exit) the normal run state and
// enables/disables all interrupts on the receiver's USB port.
func (h *hhw) enable(enable bool) {
if enable {
h.irq.Enable() // Enable USB interrupts
} else {
h.irq.Disable() // Disable USB interrupts
}
}
+67
View File
@@ -0,0 +1,67 @@
// +build mimxrt1062
package usb
// Implementation of USB host controller driver (hcd) for NXP iMXRT1062.
import (
"device/nxp"
"runtime/interrupt"
)
// hhwInterruptPriority defines the priority for all USB host interrupts.
const hhwInterruptPriority = 3
// hhw implements USB host controller hardware abstraction interface.
type hhw struct {
*hcd // USB host controller driver
bus *nxp.USB_Type // USB core register
phy *nxp.USBPHY_Type // USB PHY register
irq interrupt.Interrupt // USB IRQ, only a single interrupt on iMXRT1062
speed Speed
}
// allocHHW returns a reference to the USB hardware abstraction for the given
// host controller driver. Should be called only one time and during host
// controller initialization.
func allocHHW(port, instance int, speed Speed, hc *hcd) *hhw {
switch port {
case 0:
hhwInstance[instance].hcd = hc
hhwInstance[instance].bus = nxp.USB1
hhwInstance[instance].phy = nxp.USBPHY1
case 1:
hhwInstance[instance].hcd = hc
hhwInstance[instance].bus = nxp.USB2
hhwInstance[instance].phy = nxp.USBPHY2
}
// Both ports default to high-speed (480 Mbit/sec) on Teensy 4.x
if 0 == speed {
speed = HighSpeed
}
hhwInstance[instance].speed = speed
return &hhwInstance[instance]
}
// init configures the USB port for host mode operation by initializing all
// endpoint and transfer descriptor data structures, initializing core registers
// and interrupts, resetting the USB PHY, and enabling power on the bust.
func (h *hhw) init() status {
return statusOK
}
// enable causes the USB core to enter (or exit) the normal run state and
// enables/disables all interrupts on the receiver's USB port.
func (h *hhw) enable(enable bool) {
if enable {
h.irq.Enable() // Enable USB interrupts
} else {
h.irq.Disable() // Disable USB interrupts
}
}
+293
View File
@@ -0,0 +1,293 @@
package usb
import (
"errors"
"runtime/volatile"
)
type QueueFullDiscardMode uint8
const (
QueueFullDiscardLast QueueFullDiscardMode = iota // Drop incoming data
QueueFullDiscardFirst // Drop outgoing data
)
type Queue struct {
mode QueueFullDiscardMode
size volatile.Register32
fifo *[]uint8
tail volatile.Register32 // New elements are enqueued at index tail
head volatile.Register32 // Oldest element in queue is at index head
}
var (
ErrQueueReadZero = errors.New("copy into zero-length buffer")
ErrQueueWriteZero = errors.New("copy from zero-length buffer")
ErrQueueEmpty = errors.New("buffer empty") // Read underrun
ErrQueueFull = errors.New("buffer full") // Write overrun
ErrQueueDiscardMode = errors.New("unknown discard mode")
)
// Init initializes the receiver queue's backing data store with the given byte
// slice fifo and logical capacity size. If size is greater than the slice's
// physical length, uses the slice's physical length.
func (q *Queue) Init(fifo *[]uint8, size int, mode QueueFullDiscardMode) {
q.mode = mode
q.fifo = fifo
q.Reset(size)
}
// Reset discards all buffered data and sets the FIFO logical capacity.
// If size is less than 0 or greater than FIFO physical length, uses FIFO
// physical length.
//go:inline
func (q *Queue) Reset(size int) {
if phy := len(*q.fifo); size < 0 || size > phy {
size = phy
}
q.size.Set(uint32(size))
q.tail.Set(0)
q.head.Set(0)
}
// Cap returns the logical capacity of the receiver FIFO.
//go:inline
func (q *Queue) Cap() int {
return int(q.size.Get())
}
// Len returns the number of elements enqueued in the receiver FIFO.
//go:inline
func (q *Queue) Len() int {
return int(q.tail.Get() - q.head.Get())
}
// Rem returns the number of elements not enqueued in the receiver FIFO.
//go:inline
func (q *Queue) Rem() int {
return q.Cap() - q.Len()
}
// Deq dequeues and returns the element at the front of the receiver FIFO and true.
// If the FIFO is empty and no element was dequeued, returns 0 and false.
func (q *Queue) Deq() (uint8, bool) {
head := q.head.Get()
if head == q.tail.Get() {
return 0, false
} // empty queue
data := (*q.fifo)[head%q.size.Get()]
q.head.Set(head + 1)
return data, true
}
// Enq enqueues the given element data at the back of the receiver FIFO and
// returns true.
// If the FIFO is full and no element can be enqueued, returns false.
//
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
func (q *Queue) Enq(data uint8) bool {
tail := q.tail.Get()
head := q.head.Get()
if tail-head == q.size.Get() {
switch q.mode {
case QueueFullDiscardLast:
// drop incoming data
return false
case QueueFullDiscardFirst:
// drop outgoing data
q.head.Set(head + 1)
}
} // full queue
(*q.fifo)[tail%q.size.Get()] = data
q.tail.Set(tail + 1)
return true
}
// Read implements the io.Reader interface. It dequeues min(q.Len(), len(data))
// elements from the receiver FIFO into the given slice data.
// If len(data) equals 0, returns 0 and ErrReadBuffer.
// Otherwise, if q.Len() equals 0, returns 0 and ErrQueueEmpty.
func (q *Queue) Read(data []uint8) (int, error) {
less := uint32(len(data))
if less == 0 {
return 0, ErrQueueReadZero
} // nothing to copy into
head := q.head.Get()
used := q.tail.Get() - head
if used == 0 {
return 0, ErrQueueEmpty
} // empty queue
if less > used {
less = used
} // only get from used space
for i := uint32(0); i < less; i++ {
data[i] = (*q.fifo)[head%q.size.Get()]
head++
}
q.head.Set(head)
return int(less), nil
}
// Write implements the io.Writer interface. It enqueues min(q.Rem(), len(data))
// elements from the given slice data into the receiver FIFO.
// If len(data) equals 0, returns 0 and ErrWriteBuffer.
// Otherwise, if q.Rem() equals 0, returns 0 and ErrQueueFull.
//
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
func (q *Queue) Write(data []uint8) (int, error) {
more := uint32(len(data))
// Nothing to copy from is an error regardless of mode.
if more == 0 {
return 0, ErrQueueWriteZero
}
switch q.mode {
case QueueFullDiscardLast:
// drop incoming data
tail := q.tail.Get()
used := tail - q.head.Get()
// Full queue, cannot add any data.
if used == q.size.Get() {
return 0, ErrQueueFull
}
// Only put to unused space.
if used+more > q.size.Get() {
more = q.size.Get() - used
}
// Copy a potentially-limited number of elements from data, depending on the
// current length of FIFO.
for i := uint32(0); i < more; i++ {
(*q.fifo)[tail%q.size.Get()] = data[i]
tail++
}
q.tail.Set(tail)
return int(more), nil
case QueueFullDiscardFirst:
// drop outgoing data
// Trying to write more data than the FIFO will hold will simply overwrite
// some of the given data, so there is no point writing that data.
from := uint32(0)
if more >= q.size.Get() {
// Begin copying only the data that will be kept.
from = more - q.size.Get()
// We can fill the entire FIFO.
more = q.size.Get()
// Reset the indices
q.head.Set(0)
q.tail.Set(0)
}
tail := q.tail.Get()
used := tail - q.head.Get()
// Make space for incoming data by discarding only as many FIFO elements as
// is necessary to store incoming data.
if used+more > q.size.Get() {
q.head.Set(tail + more - q.size.Get())
}
// Copy a potentially-limited number of elements from data, depending on the
// current length of FIFO.
for i := uint32(0); i < more; i++ {
(*q.fifo)[tail%q.size.Get()] = data[from+i]
tail++
}
q.tail.Set(tail)
return int(more), nil
}
return 0, ErrQueueDiscardMode
}
// Front returns the next element that would be dequeued from the receiver FIFO
// and true.
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
func (q *Queue) Front() (uint8, bool) {
head := q.head.Get()
if head == q.tail.Get() {
return 0, false
} // empty queue
return (*q.fifo)[head%q.size.Get()], true
}
// Back returns the last element that would be dequeued from the receiver FIFO
// and true.
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
func (q *Queue) Back() (uint8, bool) {
tail := q.tail.Get()
if tail == q.head.Get() {
return 0, false
} // empty queue
return (*q.fifo)[(tail-1)%q.size.Get()], true
}
// index returns an index into the receiver FIFO based on sign and magnitude of i:
// 1. If i is greater than or equal to zero and less then q.Len(), returns the
// (i+1)'th element that would be dequeued from the receiver FIFO and true.
// 2. Otherwise, if i is negative and -i is less than or equal to q.Len(), returns
// the -(i+1)'th from the last element that would be dequeued from the receiver
// FIFO and true.
// 3. Otherwise, returns 0 and false.
func (q *Queue) index(i int) (int, bool) {
if n := q.Len(); i < 0 {
if -i <= n {
return (int(q.tail.Get()) + i) % int(q.size.Get()), true
}
} else {
if i < n {
return (int(q.head.Get()) + i) % int(q.size.Get()), true
}
}
return 0, false
}
// Get returns the value of an element in the receiver FIFO, offset by i from the
// front of the queue if i is positive, or from the back of the queue if i is
// negative. For example:
// Get(0) == Get(-Len()) == Front(), and
// Get(-1) == Get(Len()-1) == Back().
// If the offset is beyond queue boundaries, returns 0 and false.
func (q *Queue) Get(i int) (uint8, bool) {
if n, ok := q.index(i); ok {
return (*q.fifo)[n], true
}
return 0, false
}
// Set modifies the value of an element in the receiver FIFO.
// Set uses the same logic as Get to select an element in the FIFO.
func (q *Queue) Set(i int, data uint8) bool {
if n, ok := q.index(i); ok {
(*q.fifo)[n] = data
return true
}
return false
}
+83
View File
@@ -0,0 +1,83 @@
//go:build usb.cdc
// +build usb.cdc
package usb
import (
"errors"
)
var (
ErrCDCInvalidPort = errors.New("invalid port")
ErrCDCEmptyBuffer = errors.New("buffer empty")
)
// CDC represents a virtual UART serial device emulation using the USB
// CDC-ACM device class driver.
type CDC struct {
// Port is the MCU's native USB core number. If in doubt, leave it
// uninitialized for default (0).
Port int
core *core
}
type CDCConfig struct {
BusSpeed Speed
}
func (cdc *CDC) Configure(config CDCConfig) error {
c := class{id: classDeviceCDC, config: 1}
// verify we have a free USB port and take ownership of it
var st status
cdc.core, st = initCore(cdc.Port, config.BusSpeed, c)
if !st.ok() {
return ErrCDCInvalidPort
}
return nil
}
func (cdc *CDC) Ready() bool {
return cdc.core.dc.cdcReady()
}
// Buffered returns the number of bytes currently stored in the Rx buffer.
func (cdc *CDC) Buffered() int {
for !cdc.Ready() {
}
return cdc.core.dc.cdcAvailable()
}
// ReadByte reads a single byte from the Rx buffer.
// If there is no data in the buffer, returns an error.
func (cdc *CDC) ReadByte() (byte, error) {
for !cdc.Ready() {
}
n, ok := cdc.core.dc.cdcReadByte()
if !ok {
return 0, ErrCDCEmptyBuffer
}
return n, nil
}
// Read from the Rx buffer.
func (cdc *CDC) Read(data []byte) (n int, err error) {
for !cdc.Ready() {
}
return cdc.core.dc.cdcRead(data)
}
// WriteByte writes a single byte of data to the virtual UART interface.
func (cdc *CDC) WriteByte(c byte) error {
for !cdc.Ready() {
}
return cdc.core.dc.cdcWriteByte(c)
}
// Write data to the virtual UART.
func (cdc *CDC) Write(data []byte) (n int, err error) {
for !cdc.Ready() {
}
return cdc.core.dc.cdcWrite(data)
}
+965
View File
@@ -0,0 +1,965 @@
//go:build usb.hid
// +build usb.hid
package usb
import "errors"
var (
ErrInvalidCodepoint = errors.New("invalid Unicode codepoint")
ErrInvalidKeycode = errors.New("invalid keyboard keycode")
ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding")
ErrKeypressMaximum = errors.New("maximum keypresses exceeded")
)
// Keyboard represents a USB HID keyboard device with support for international
// layouts and various control, system, multimedia, and consumer keycodes.
//
// Keyboard implements the io.Writer interface that translates UTF-8 encoded
// byte strings into sequences of keypress events.
type Keyboard struct {
dc *dcd
hc *descHIDClass
// led holds the current state of all keyboard LEDs:
// 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana
led uint8
// mod holds the current state of all keyboard modifier keys:
// 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI
// 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI
mod uint8
// key holds a list of all keyboard keys currently pressed.
key *[hidKeyboardKeyCount]uint8
con *[hidKeyboardConCount]uint16
sys *[hidKeyboardSysCount]uint8
// decode holds the current state of the UTF-8 decoder.
decode decodeState
// wideChar holds high bits for the UTF-8 decoder.
wideChar uint16
}
// decodeState represents a state in the UTF-8 decode state machine.
type decodeState uint8
// Constant enumerated values of type decodeState.
const (
decodeReset decodeState = iota
decodeByte1
decodeByte2
decodeByte3
)
// configure initializes the receiver Keyboard by associating it with the given
// USB device controller driver and HID class configuration.
func (kb *Keyboard) configure(dc *dcd, hc *descHIDClass) {
kb.dc = dc
kb.hc = hc
}
func (kb *Keyboard) ready() bool {
return kb.dc != nil && kb.hc != nil
}
// Write transmits press-and-release key sequences for each Keycode translated
// from the given UTF-8 byte string. Write implements the io.Writer interface
// and conforms to all documented conventions for arguments and return values.
func (kb *Keyboard) Write(b []byte) (n int, err error) {
for _, c := range b {
if err = kb.WriteByte(c); nil != err {
break
}
n += 1
}
return
}
// WriteByte processes a single byte from a UTF-8 byte string. This method is a
// stateful method with respect to the receiver Keyboard, meaning that its exact
// behavior will depend on the current state of its UTF-8 decode state machine:
//
// (a) If the given byte is a valid ASCII encoding (0-127), then a keypress
// sequence is immediately transmitted for the respective Keycode.
//
// (b) If the given byte represents the final byte in a multi-byte codepoint,
// then a keypress sequence is immediately transmitted by translating the
// multi-byte codepoint to its respective Keycode.
//
// (c) If the given byte appears to represent high bits for a multi-byte
// codepoint, then the bits are copied to the receiver's internal state
// machine buffer for use by a subsequent call to WriteByte() (or Write())
// that completes the codepoint.
//
// (d) If the given byte is out of range, or contains illegal bits for the
// current state of the UTF-8 decoder, then the UTF-8 decode state machine
// is reset to its initial state.
//
// In cases (c) and (d), a keypress sequence is not generated and no data is
// transmitted. In case (c), additional bytes must be received via WriteByte()
// (or Write()) to complete or discard the current codepoint.
func (kb *Keyboard) WriteByte(b byte) error {
switch {
case b < 0x80:
// 1-byte encoding (0x00-0x7F)
kb.decode = decodeByte1
return kb.write(uint16(b))
case b < 0xC0:
// 2nd, 3rd, or 4th byte (0x80-0xBF)
b = Keycode(b).key()
switch kb.decode {
case decodeByte2:
kb.decode = decodeByte1
return kb.write(kb.wideChar | uint16(b))
case decodeByte3:
kb.decode = decodeByte2
kb.wideChar |= uint16(b) << 6
}
case b < 0xE0:
// 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1)
kb.decode = decodeByte2
kb.wideChar = uint16(b&0x1F) << 6
case b < 0xF0:
// 3-byte encoding (0xE0-0xEF)
kb.decode = decodeByte3
kb.wideChar = uint16(b&0x0F) << 12
default:
// 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF)
kb.decode = decodeReset
return ErrInvalidUTF8
}
return nil
}
func (kb *Keyboard) write(p uint16) error {
c := keycode(p)
if 0 == c {
return ErrInvalidCodepoint
}
if d := deadkey(c); 0 != d {
if err := kb.writeKeycode(d); nil != err {
return err
}
}
return kb.writeKeycode(c)
}
func (kb *Keyboard) writeKeycode(c Keycode) error {
kb.mod = c.mod()
kb.key[0] = c.key()
kb.key[1] = 0
kb.key[2] = 0
kb.key[3] = 0
kb.key[4] = 0
kb.key[5] = 0
if !kb.dc.keyboardSendKeys(false) {
return ErrHIDReportTransfer
}
kb.mod = 0
kb.key[0] = 0
if !kb.dc.keyboardSendKeys(false) {
return ErrHIDReportTransfer
}
return nil
}
// Press transmits a press-and-release sequence for the given Keycode, which
// simulates a discrete keypress event.
//
// The following values of Keycode are supported:
//
// 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT]
// 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT]
// 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT]
// 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI)
// 0xE200 - 0xE2FF System key (HID usage code, page 1)
// 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12)
// 0xF000 - 0xFFFF Normal key (HID usage code, page 7)
func (kb *Keyboard) Press(c Keycode) error {
if err := kb.Down(c); nil != err {
return err
}
return kb.Up(c)
}
// Down transmits a key-down event for the given Keycode.
//
// The host will interpret the key as being held down continuously until a
// corresponding key-up event is transmitted, e.g., via method Up().
//
// See godoc comment on method Press() for details on what input is accepted and
// how it is interpreted.
func (kb *Keyboard) Down(c Keycode) error {
var res uint8
msb := c >> 8
if msb >= 0xC2 {
if msb < 0xE0 {
c = ((msb & 0x1F) << 6) | Keycode(c.key())
} else {
switch msb {
case 0xF0:
return kb.down(uint8(c), 0)
case 0xE0:
return kb.down(0, uint8(c))
case 0xE2:
return kb.downSys(uint8(c))
default:
if 0xE4 <= msb && msb <= 0xE7 {
return kb.downCon(uint16(c & 0x03FF))
}
return ErrInvalidKeycode
}
}
}
c = keycode(uint16(c))
if 0 == c {
return ErrInvalidCodepoint
}
if d := deadkey(c); 0 != d {
res = kb.mod
if 0 != res {
kb.mod = 0
kb.dc.keyboardSendKeys(false)
}
kb.down(d.key(), d.mod())
kb.up(d.key(), d.mod())
}
return kb.down(c.key(), c.mod()|res)
}
func (kb *Keyboard) down(key uint8, mod uint8) error {
send := false
if 0 != mod {
if kb.mod&mod != mod {
kb.mod |= mod
send = true
}
}
if 0 != key {
for _, k := range kb.key {
if k == key {
goto end
}
}
for i, k := range kb.key {
if 0 == k {
kb.key[i] = key
send = true
goto end
}
}
return ErrKeypressMaximum
}
end:
if send {
if !kb.dc.keyboardSendKeys(false) {
return ErrHIDReportTransfer
}
}
return nil
}
func (kb *Keyboard) downCon(key uint16) error {
if 0 == key {
return ErrInvalidKeycode
}
for _, k := range kb.con {
if key == k {
return nil // already pressed
}
}
for i, k := range kb.con {
if 0 == k {
kb.con[i] = key
if !kb.dc.keyboardSendKeys(true) {
return ErrHIDReportTransfer
}
return nil
}
}
return ErrKeypressMaximum
}
func (kb *Keyboard) downSys(key uint8) error {
if 0 == key {
return ErrInvalidKeycode
}
for _, k := range kb.sys {
if key == k {
return nil // already pressed
}
}
for i, k := range kb.sys {
if 0 == k {
kb.sys[i] = key
if !kb.dc.keyboardSendKeys(true) {
return ErrHIDReportTransfer
}
return nil
}
}
return ErrKeypressMaximum
}
// Up transmits a key-up event for the given Keycode.
//
// See godoc comment on method Press() for details on what input is accepted and
// how it is interpreted.
func (kb *Keyboard) Up(c Keycode) error {
msb := c >> 8
if msb >= 0xC2 {
if msb < 0xE0 {
c = ((msb & 0x1F) << 6) | Keycode(c.key())
} else {
switch msb {
case 0xF0:
return kb.up(uint8(c), 0)
case 0xE0:
return kb.up(0, uint8(c))
case 0xE2:
return kb.upSys(uint8(c))
default:
if 0xE4 <= msb && msb <= 0xE7 {
return kb.upCon(uint16(c & 0x03FF))
}
return ErrInvalidKeycode
}
}
}
c = keycode(uint16(c))
if 0 == c {
return ErrInvalidCodepoint
}
return kb.up(c.key(), c.mod())
}
// Release transmits a key-up event for all keyboard keys currently pressed as
// if the user removed his/her hands from the keyboard entirely.
func (kb *Keyboard) Release() error {
bits := uint16(kb.mod)
kb.mod = 0
for i, k := range kb.key {
bits |= uint16(k)
kb.key[i] = 0
}
if 0 != bits {
if !kb.dc.keyboardSendKeys(false) {
return ErrHIDReportTransfer
}
}
bits = 0
for i, k := range kb.con {
bits |= k
kb.con[i] = 0
}
for i, k := range kb.sys {
bits |= uint16(k)
kb.sys[i] = 0
}
if 0 != bits {
if !kb.dc.keyboardSendKeys(true) {
return ErrHIDReportTransfer
}
}
return nil
}
func (kb *Keyboard) up(key uint8, mod uint8) error {
send := false
if 0 != mod {
if kb.mod&mod != 0 {
kb.mod &^= mod
send = true
}
}
if 0 != key {
for i, k := range kb.key {
if key == k {
kb.key[i] = 0
send = true
}
}
}
if send {
if !kb.dc.keyboardSendKeys(false) {
return ErrHIDReportTransfer
}
}
return nil
}
func (kb *Keyboard) upCon(key uint16) error {
if 0 == key {
return ErrInvalidKeycode
}
for i, k := range kb.con {
if key == k {
kb.con[i] = 0
if !kb.dc.keyboardSendKeys(true) {
return ErrHIDReportTransfer
}
return nil
}
}
return nil
}
func (kb *Keyboard) upSys(key uint8) error {
if 0 == key {
return ErrInvalidKeycode
}
for i, k := range kb.sys {
if key == k {
kb.sys[i] = 0
if !kb.dc.keyboardSendKeys(true) {
return ErrHIDReportTransfer
}
return nil
}
}
return nil
}
// Keycode is a package-defined bitmap used to encode the value of a given key.
type Keycode uint16
// keycode returns the given Unicode codepoint translated to a Keycode sequence.
// Unicode codepoints greater than U+FFFF are unsupported.
//go:inline
func keycode(p uint16) Keycode {
if p < 0x80 {
return ascii[p]
} else if p >= 0xA0 && p < 0x0100 {
return iso88591[p-0xA0]
} else if uint16(UNICODE20AC) == p {
return UNICODE20AC.mask()
}
return 0
}
//go:inline
func deadkey(c Keycode) Keycode {
switch c & deadkeysMask {
case acuteAccentBits:
return deadkeyAcuteAccent
case circumflexBits:
return deadkeyCircumflex
case diaeresisBits:
return deadkeyDiaeresis
case graveAccentBits:
return deadkeyGraveAccent
case tildeBits:
return deadkeyTilde
}
return 0
}
//go:inline
func (c Keycode) mask() Keycode { return c & keycodeMask }
//go:inline
func (c Keycode) key() uint8 { return uint8(c & keyMask) }
//go:inline
func (c Keycode) mod() uint8 {
var m Keycode
if 0 != c&shiftMask {
m |= KeyModifierShift
}
if 0 != c&altgrMask {
m |= KeyModifierRightAlt
}
return uint8(m)
}
//go:inline
func (c Keycode) Shift() Keycode { return c | KeyModifierShift }
const (
hidKeyboardKeyCount = 6 // Max number of simultaneous keypresses
hidKeyboardSysCount = 3
hidKeyboardConCount = 4
)
// Keycodes common to all Keyboard layouts
const (
KeyModifierCtrl Keycode = 0x01 | 0xE000
KeyModifierShift Keycode = 0x02 | 0xE000
KeyModifierAlt Keycode = 0x04 | 0xE000
KeyModifierGUI Keycode = 0x08 | 0xE000
KeyModifierLeftCtrl Keycode = 0x01 | 0xE000
KeyModifierLeftShift Keycode = 0x02 | 0xE000
KeyModifierLeftAlt Keycode = 0x04 | 0xE000
KeyModifierLeftGUI Keycode = 0x08 | 0xE000
KeyModifierRightCtrl Keycode = 0x10 | 0xE000
KeyModifierRightShift Keycode = 0x20 | 0xE000
KeyModifierRightAlt Keycode = 0x40 | 0xE000
KeyModifierRightGUI Keycode = 0x80 | 0xE000
KeySystemPowerDown Keycode = 0x81 | 0xE200
KeySystemSleep Keycode = 0x82 | 0xE200
KeySystemWakeUp Keycode = 0x83 | 0xE200
KeyMediaPlay Keycode = 0xB0 | 0xE400
KeyMediaPause Keycode = 0xB1 | 0xE400
KeyMediaRecord Keycode = 0xB2 | 0xE400
KeyMediaFastForward Keycode = 0xB3 | 0xE400
KeyMediaRewind Keycode = 0xB4 | 0xE400
KeyMediaNextTrack Keycode = 0xB5 | 0xE400
KeyMediaPrevTrack Keycode = 0xB6 | 0xE400
KeyMediaStop Keycode = 0xB7 | 0xE400
KeyMediaEject Keycode = 0xB8 | 0xE400
KeyMediaRandomPlay Keycode = 0xB9 | 0xE400
KeyMediaPlayPause Keycode = 0xCD | 0xE400
KeyMediaPlaySkip Keycode = 0xCE | 0xE400
KeyMediaMute Keycode = 0xE2 | 0xE400
KeyMediaVolumeInc Keycode = 0xE9 | 0xE400
KeyMediaVolumeDec Keycode = 0xEA | 0xE400
KeyA Keycode = 4 | 0xF000
KeyB Keycode = 5 | 0xF000
KeyC Keycode = 6 | 0xF000
KeyD Keycode = 7 | 0xF000
KeyE Keycode = 8 | 0xF000
KeyF Keycode = 9 | 0xF000
KeyG Keycode = 10 | 0xF000
KeyH Keycode = 11 | 0xF000
KeyI Keycode = 12 | 0xF000
KeyJ Keycode = 13 | 0xF000
KeyK Keycode = 14 | 0xF000
KeyL Keycode = 15 | 0xF000
KeyM Keycode = 16 | 0xF000
KeyN Keycode = 17 | 0xF000
KeyO Keycode = 18 | 0xF000
KeyP Keycode = 19 | 0xF000
KeyQ Keycode = 20 | 0xF000
KeyR Keycode = 21 | 0xF000
KeyS Keycode = 22 | 0xF000
KeyT Keycode = 23 | 0xF000
KeyU Keycode = 24 | 0xF000
KeyV Keycode = 25 | 0xF000
KeyW Keycode = 26 | 0xF000
KeyX Keycode = 27 | 0xF000
KeyY Keycode = 28 | 0xF000
KeyZ Keycode = 29 | 0xF000
Key1 Keycode = 30 | 0xF000
Key2 Keycode = 31 | 0xF000
Key3 Keycode = 32 | 0xF000
Key4 Keycode = 33 | 0xF000
Key5 Keycode = 34 | 0xF000
Key6 Keycode = 35 | 0xF000
Key7 Keycode = 36 | 0xF000
Key8 Keycode = 37 | 0xF000
Key9 Keycode = 38 | 0xF000
Key0 Keycode = 39 | 0xF000
KeyEnter Keycode = 40 | 0xF000
KeyEsc Keycode = 41 | 0xF000
KeyBackspace Keycode = 42 | 0xF000
KeyTab Keycode = 43 | 0xF000
KeySpace Keycode = 44 | 0xF000
KeyMinus Keycode = 45 | 0xF000
KeyEqual Keycode = 46 | 0xF000
KeyLeftBrace Keycode = 47 | 0xF000
KeyRightBrace Keycode = 48 | 0xF000
KeyBackslash Keycode = 49 | 0xF000
KeyNonUsNum Keycode = 50 | 0xF000
KeySemicolon Keycode = 51 | 0xF000
KeyQuote Keycode = 52 | 0xF000
KeyTilde Keycode = 53 | 0xF000
KeyComma Keycode = 54 | 0xF000
KeyPeriod Keycode = 55 | 0xF000
KeySlash Keycode = 56 | 0xF000
KeyCapsLock Keycode = 57 | 0xF000
KeyF1 Keycode = 58 | 0xF000
KeyF2 Keycode = 59 | 0xF000
KeyF3 Keycode = 60 | 0xF000
KeyF4 Keycode = 61 | 0xF000
KeyF5 Keycode = 62 | 0xF000
KeyF6 Keycode = 63 | 0xF000
KeyF7 Keycode = 64 | 0xF000
KeyF8 Keycode = 65 | 0xF000
KeyF9 Keycode = 66 | 0xF000
KeyF10 Keycode = 67 | 0xF000
KeyF11 Keycode = 68 | 0xF000
KeyF12 Keycode = 69 | 0xF000
KeyPrintscreen Keycode = 70 | 0xF000
KeyScrollLock Keycode = 71 | 0xF000
KeyPause Keycode = 72 | 0xF000
KeyInsert Keycode = 73 | 0xF000
KeyHome Keycode = 74 | 0xF000
KeyPageUp Keycode = 75 | 0xF000
KeyDelete Keycode = 76 | 0xF000
KeyEnd Keycode = 77 | 0xF000
KeyPageDown Keycode = 78 | 0xF000
KeyRight Keycode = 79 | 0xF000
KeyLeft Keycode = 80 | 0xF000
KeyDown Keycode = 81 | 0xF000
KeyUp Keycode = 82 | 0xF000
KeyNumLock Keycode = 83 | 0xF000
KeypadSlash Keycode = 84 | 0xF000
KeypadAsterisk Keycode = 85 | 0xF000
KeypadMinus Keycode = 86 | 0xF000
KeypadPlus Keycode = 87 | 0xF000
KeypadEnter Keycode = 88 | 0xF000
Keypad1 Keycode = 89 | 0xF000
Keypad2 Keycode = 90 | 0xF000
Keypad3 Keycode = 91 | 0xF000
Keypad4 Keycode = 92 | 0xF000
Keypad5 Keycode = 93 | 0xF000
Keypad6 Keycode = 94 | 0xF000
Keypad7 Keycode = 95 | 0xF000
Keypad8 Keycode = 96 | 0xF000
Keypad9 Keycode = 97 | 0xF000
Keypad0 Keycode = 98 | 0xF000
KeypadPeriod Keycode = 99 | 0xF000
KeyNonUSBS Keycode = 100 | 0xF000
KeyMenu Keycode = 101 | 0xF000
KeyF13 Keycode = 104 | 0xF000
KeyF14 Keycode = 105 | 0xF000
KeyF15 Keycode = 106 | 0xF000
KeyF16 Keycode = 107 | 0xF000
KeyF17 Keycode = 108 | 0xF000
KeyF18 Keycode = 109 | 0xF000
KeyF19 Keycode = 110 | 0xF000
KeyF20 Keycode = 111 | 0xF000
KeyF21 Keycode = 112 | 0xF000
KeyF22 Keycode = 113 | 0xF000
KeyF23 Keycode = 114 | 0xF000
KeyF24 Keycode = 115 | 0xF000
KeyUpArrow Keycode = KeyUp
KeyDownArrow Keycode = KeyDown
KeyLeftArrow Keycode = KeyLeft
KeyRightArrow Keycode = KeyRight
KeyReturn Keycode = KeyEnter
KeyLeftCtrl Keycode = KeyModifierLeftCtrl
KeyLeftShift Keycode = KeyModifierLeftShift
KeyLeftAlt Keycode = KeyModifierLeftAlt
KeyLeftGUI Keycode = KeyModifierLeftGUI
KeyRightCtrl Keycode = KeyModifierRightCtrl
KeyRightShift Keycode = KeyModifierRightShift
KeyRightAlt Keycode = KeyModifierRightAlt
KeyRightGUI Keycode = KeyModifierRightGUI
)
// Keycodes for layout US English (0x0904)
const (
keycodeMask Keycode = 0x07FF
keyMask Keycode = 0x003F
shiftMask Keycode = 0x0040
altgrMask Keycode = 0x0080
deadkeysMask Keycode = 0x0700
circumflexBits Keycode = 0x0100
acuteAccentBits Keycode = 0x0200
graveAccentBits Keycode = 0x0300
tildeBits Keycode = 0x0400
diaeresisBits Keycode = 0x0500
deadkeyCircumflex Keycode = Key6 | shiftMask
deadkeyAcuteAccent Keycode = KeyQuote
deadkeyGraveAccent Keycode = KeyTilde
deadkeyTilde Keycode = KeyTilde | shiftMask
deadkeyDiaeresis Keycode = KeyQuote | shiftMask
ASCII00 Keycode = 0 // 0 NUL
ASCII01 Keycode = 0 // 1 SOH
ASCII02 Keycode = 0 // 2 STX
ASCII03 Keycode = 0 // 3 ETX
ASCII04 Keycode = 0 // 4 EOT
ASCII05 Keycode = 0 // 5 ENQ
ASCII06 Keycode = 0 // 6 ACK
ASCII07 Keycode = 0 // 7 BEL
ASCII08 Keycode = KeyBackspace // 8 BS
ASCII09 Keycode = KeyTab // 9 TAB
ASCII0A Keycode = KeyEnter // 10 LF
ASCII0B Keycode = 0 // 11 VT
ASCII0C Keycode = 0 // 12 FF
ASCII0D Keycode = 0 // 13 CR
ASCII0E Keycode = 0 // 14 SO
ASCII0F Keycode = 0 // 15 SI
ASCII10 Keycode = 0 // 16 DEL
ASCII11 Keycode = 0 // 17 DC1
ASCII12 Keycode = 0 // 18 DC2
ASCII13 Keycode = 0 // 19 DC3
ASCII14 Keycode = 0 // 20 DC4
ASCII15 Keycode = 0 // 21 NAK
ASCII16 Keycode = 0 // 22 SYN
ASCII17 Keycode = 0 // 23 ETB
ASCII18 Keycode = 0 // 24 CAN
ASCII19 Keycode = 0 // 25 EM
ASCII1A Keycode = 0 // 26 SUB
ASCII1B Keycode = 0 // 27 ESC
ASCII1C Keycode = 0 // 28 FS
ASCII1D Keycode = 0 // 29 GS
ASCII1E Keycode = 0 // 30 RS
ASCII1F Keycode = 0 // 31 US
ASCII20 Keycode = KeySpace // 32 SPACE
ASCII21 Keycode = Key1 | shiftMask // 33 !
ASCII22 Keycode = diaeresisBits | KeySpace // 34 "
ASCII23 Keycode = Key3 | shiftMask // 35 #
ASCII24 Keycode = Key4 | shiftMask // 36 $
ASCII25 Keycode = Key5 | shiftMask // 37 %
ASCII26 Keycode = Key7 | shiftMask // 38 &
ASCII27 Keycode = acuteAccentBits | KeySpace // 39 '
ASCII28 Keycode = Key9 | shiftMask // 40 (
ASCII29 Keycode = Key0 | shiftMask // 41 )
ASCII2A Keycode = Key8 | shiftMask // 42 *
ASCII2B Keycode = KeyEqual | shiftMask // 43 +
ASCII2C Keycode = KeyComma // 44 ,
ASCII2D Keycode = KeyMinus // 45 -
ASCII2E Keycode = KeyPeriod // 46 .
ASCII2F Keycode = KeySlash // 47 /
ASCII30 Keycode = Key0 // 48 0
ASCII31 Keycode = Key1 // 49 1
ASCII32 Keycode = Key2 // 50 2
ASCII33 Keycode = Key3 // 51 3
ASCII34 Keycode = Key4 // 52 4
ASCII35 Keycode = Key5 // 53 5
ASCII36 Keycode = Key6 // 54 6
ASCII37 Keycode = Key7 // 55 7
ASCII38 Keycode = Key8 // 55 8
ASCII39 Keycode = Key9 // 57 9
ASCII3A Keycode = KeySemicolon | shiftMask // 58 :
ASCII3B Keycode = KeySemicolon // 59 ;
ASCII3C Keycode = KeyComma | shiftMask // 60 <
ASCII3D Keycode = KeyEqual // 61 =
ASCII3E Keycode = KeyPeriod | shiftMask // 62 >
ASCII3F Keycode = KeySlash | shiftMask // 63 ?
ASCII40 Keycode = Key2 | shiftMask // 64 @
ASCII41 Keycode = KeyA | shiftMask // 65 A
ASCII42 Keycode = KeyB | shiftMask // 66 B
ASCII43 Keycode = KeyC | shiftMask // 67 C
ASCII44 Keycode = KeyD | shiftMask // 68 D
ASCII45 Keycode = KeyE | shiftMask // 69 E
ASCII46 Keycode = KeyF | shiftMask // 70 F
ASCII47 Keycode = KeyG | shiftMask // 71 G
ASCII48 Keycode = KeyH | shiftMask // 72 H
ASCII49 Keycode = KeyI | shiftMask // 73 I
ASCII4A Keycode = KeyJ | shiftMask // 74 J
ASCII4B Keycode = KeyK | shiftMask // 75 K
ASCII4C Keycode = KeyL | shiftMask // 76 L
ASCII4D Keycode = KeyM | shiftMask // 77 M
ASCII4E Keycode = KeyN | shiftMask // 78 N
ASCII4F Keycode = KeyO | shiftMask // 79 O
ASCII50 Keycode = KeyP | shiftMask // 80 P
ASCII51 Keycode = KeyQ | shiftMask // 81 Q
ASCII52 Keycode = KeyR | shiftMask // 82 R
ASCII53 Keycode = KeyS | shiftMask // 83 S
ASCII54 Keycode = KeyT | shiftMask // 84 T
ASCII55 Keycode = KeyU | shiftMask // 85 U
ASCII56 Keycode = KeyV | shiftMask // 86 V
ASCII57 Keycode = KeyW | shiftMask // 87 W
ASCII58 Keycode = KeyX | shiftMask // 88 X
ASCII59 Keycode = KeyY | shiftMask // 89 Y
ASCII5A Keycode = KeyZ | shiftMask // 90 Z
ASCII5B Keycode = KeyLeftBrace // 91 [
ASCII5C Keycode = KeyBackslash // 92 \
ASCII5D Keycode = KeyRightBrace // 93 ]
ASCII5E Keycode = circumflexBits | KeySpace // 94 ^
ASCII5F Keycode = KeyMinus | shiftMask // 95
ASCII60 Keycode = graveAccentBits | KeySpace // 96 `
ASCII61 Keycode = KeyA // 97 a
ASCII62 Keycode = KeyB // 98 b
ASCII63 Keycode = KeyC // 99 c
ASCII64 Keycode = KeyD // 100 d
ASCII65 Keycode = KeyE // 101 e
ASCII66 Keycode = KeyF // 102 f
ASCII67 Keycode = KeyG // 103 g
ASCII68 Keycode = KeyH // 104 h
ASCII69 Keycode = KeyI // 105 i
ASCII6A Keycode = KeyJ // 106 j
ASCII6B Keycode = KeyK // 107 k
ASCII6C Keycode = KeyL // 108 l
ASCII6D Keycode = KeyM // 109 m
ASCII6E Keycode = KeyN // 110 n
ASCII6F Keycode = KeyO // 111 o
ASCII70 Keycode = KeyP // 112 p
ASCII71 Keycode = KeyQ // 113 q
ASCII72 Keycode = KeyR // 114 r
ASCII73 Keycode = KeyS // 115 s
ASCII74 Keycode = KeyT // 116 t
ASCII75 Keycode = KeyU // 117 u
ASCII76 Keycode = KeyV // 118 v
ASCII77 Keycode = KeyW // 119 w
ASCII78 Keycode = KeyX // 120 x
ASCII79 Keycode = KeyY // 121 y
ASCII7A Keycode = KeyZ // 122 z
ASCII7B Keycode = KeyLeftBrace | shiftMask // 123 {
ASCII7C Keycode = KeyBackslash | shiftMask // 124 |
ASCII7D Keycode = KeyRightBrace | shiftMask // 125 }
ASCII7E Keycode = tildeBits | KeySpace // 126 ~
ASCII7F Keycode = KeyBackspace // 127 DEL
ISO88591A0 Keycode = KeySpace // 160 Nonbreakng Space
ISO88591A1 Keycode = Key1 | altgrMask // 161 ¡ Inverted Exclamation
ISO88591A2 Keycode = KeyC | altgrMask | shiftMask // 162 ¢ Cent SIGN
ISO88591A3 Keycode = Key4 | altgrMask | shiftMask // 163 £ Pound Sign
ISO88591A4 Keycode = Key4 | altgrMask // 164 ¤ Currency or Euro Sign
ISO88591A5 Keycode = KeyMinus | altgrMask // 165 ¥ YEN SIGN
ISO88591A6 Keycode = KeyBackslash | altgrMask | shiftMask // 166 ¦ BROKEN BAR ??
ISO88591A7 Keycode = KeyS | altgrMask | shiftMask // 167 § SECTION SIGN
ISO88591A8 Keycode = KeyQuote | altgrMask | shiftMask // 168 ¨ DIAERESIS
ISO88591A9 Keycode = KeyC | altgrMask // 169 © COPYRIGHT SIGN
ISO88591AA Keycode = 0 // 170 ª FEMININE ORDINAL
ISO88591AB Keycode = KeyLeftBrace | altgrMask // 171 « LEFT DOUBLE ANGLE QUOTE
ISO88591AC Keycode = KeyBackslash | altgrMask // 172 ¬ NOT SIGN ??
ISO88591AD Keycode = 0 // 173 SOFT HYPHEN
ISO88591AE Keycode = KeyR | altgrMask // 174 ® REGISTERED SIGN
ISO88591AF Keycode = 0 // 175 ¯ MACRON
ISO88591B0 Keycode = KeySemicolon | altgrMask | shiftMask // 176 ° DEGREE SIGN
ISO88591B1 Keycode = 0 // 177 ± PLUS-MINUS SIGN
ISO88591B2 Keycode = Key2 | altgrMask // 178 ² SUPERSCRIPT TWO
ISO88591B3 Keycode = Key3 | altgrMask // 179 ³ SUPERSCRIPT THREE
ISO88591B4 Keycode = KeyQuote | altgrMask // 180 ´ ACUTE ACCENT
ISO88591B5 Keycode = KeyM | altgrMask // 181 µ MICRO SIGN
ISO88591B6 Keycode = KeySemicolon | altgrMask // 182 ¶ PILCROW SIGN
ISO88591B7 Keycode = 0 // 183 · MIDDLE DOT
ISO88591B8 Keycode = 0 // 184 ¸ CEDILLA
ISO88591B9 Keycode = Key1 | altgrMask | shiftMask // 185 ¹ SUPERSCRIPT ONE
ISO88591BA Keycode = 0 // 186 º MASCULINE ORDINAL
ISO88591BB Keycode = KeyRightBrace | altgrMask // 187 » RIGHT DOUBLE ANGLE QUOTE
ISO88591BC Keycode = Key6 | altgrMask // 188 ¼ FRACTION ONE QUARTER
ISO88591BD Keycode = Key7 | altgrMask // 189 ½ FRACTION ONE HALF
ISO88591BE Keycode = Key8 | altgrMask // 190 ¾ FRACTION THREE QUARTERS
ISO88591BF Keycode = KeySlash | altgrMask // 191 ¿ INVERTED QUESTION MARK
ISO88591C0 Keycode = graveAccentBits | KeyA | shiftMask // 192 À A GRAVE
ISO88591C1 Keycode = KeyA | altgrMask | shiftMask // 193 Á A ACUTE
ISO88591C2 Keycode = circumflexBits | KeyA | shiftMask // 194 Â A CIRCUMFLEX
ISO88591C3 Keycode = tildeBits | KeyA | shiftMask // 195 Ã A TILDE
ISO88591C4 Keycode = KeyQ | altgrMask | shiftMask // 196 Ä A DIAERESIS
ISO88591C5 Keycode = KeyW | altgrMask | shiftMask // 197 Å A RING ABOVE
ISO88591C6 Keycode = KeyZ | altgrMask | shiftMask // 198 Æ AE
ISO88591C7 Keycode = KeyComma | altgrMask | shiftMask // 199 Ç C CEDILLA
ISO88591C8 Keycode = graveAccentBits | KeyE | shiftMask // 200 È E GRAVE
ISO88591C9 Keycode = KeyE | altgrMask | shiftMask // 201 É E ACUTE
ISO88591CA Keycode = circumflexBits | KeyE | shiftMask // 202 Ê E CIRCUMFLEX
ISO88591CB Keycode = diaeresisBits | KeyE | shiftMask // 203 Ë E DIAERESIS
ISO88591CC Keycode = graveAccentBits | KeyI | shiftMask // 204 Ì I GRAVE
ISO88591CD Keycode = KeyI | altgrMask | shiftMask // 205 Í I ACUTE
ISO88591CE Keycode = circumflexBits | KeyI | shiftMask // 206 Î I CIRCUMFLEX
ISO88591CF Keycode = diaeresisBits | KeyI | shiftMask // 207 Ï I DIAERESIS
ISO88591D0 Keycode = KeyD | altgrMask | shiftMask // 208 Ð ETH
ISO88591D1 Keycode = KeyN | altgrMask | shiftMask // 209 Ñ N TILDE
ISO88591D2 Keycode = graveAccentBits | KeyO | shiftMask // 210 Ò O GRAVE
ISO88591D3 Keycode = KeyO | altgrMask | shiftMask // 211 Ó O ACUTE
ISO88591D4 Keycode = circumflexBits | KeyO | shiftMask // 212 Ô O CIRCUMFLEX
ISO88591D5 Keycode = tildeBits | KeyO | shiftMask // 213 Õ O TILDE
ISO88591D6 Keycode = KeyP | altgrMask | shiftMask // 214 Ö O DIAERESIS
ISO88591D7 Keycode = KeyEqual | altgrMask // 215 × MULTIPLICATION
ISO88591D8 Keycode = KeyL | altgrMask | shiftMask // 216 Ø O STROKE
ISO88591D9 Keycode = graveAccentBits | KeyU | shiftMask // 217 Ù U GRAVE
ISO88591DA Keycode = KeyU | altgrMask | shiftMask // 218 Ú U ACUTE
ISO88591DB Keycode = circumflexBits | KeyU | shiftMask // 219 Û U CIRCUMFLEX
ISO88591DC Keycode = KeyY | altgrMask | shiftMask // 220 Ü U DIAERESIS
ISO88591DD Keycode = acuteAccentBits | KeyY | shiftMask // 221 Ý Y ACUTE
ISO88591DE Keycode = KeyT | altgrMask | shiftMask // 222 Þ THORN
ISO88591DF Keycode = KeyS | altgrMask // 223 ß SHARP S
ISO88591E0 Keycode = graveAccentBits | KeyA // 224 à a GRAVE
ISO88591E1 Keycode = KeyA | altgrMask // 225 á a ACUTE
ISO88591E2 Keycode = circumflexBits | KeyA // 226 â a CIRCUMFLEX
ISO88591E3 Keycode = tildeBits | KeyA // 227 ã a TILDE
ISO88591E4 Keycode = diaeresisBits | KeyA // 228 ä a DIAERESIS
ISO88591E5 Keycode = KeyW | altgrMask // 229 å a RING ABOVE
ISO88591E6 Keycode = KeyZ | altgrMask // 230 æ ae
ISO88591E7 Keycode = KeyComma | altgrMask // 231 ç c CEDILLA
ISO88591E8 Keycode = graveAccentBits | KeyE // 232 è e GRAVE
ISO88591E9 Keycode = acuteAccentBits | KeyE // 233 é e ACUTE
ISO88591EA Keycode = circumflexBits | KeyE // 234 ê e CIRCUMFLEX
ISO88591EB Keycode = diaeresisBits | KeyE // 235 ë e DIAERESIS
ISO88591EC Keycode = graveAccentBits | KeyI // 236 ì i GRAVE
ISO88591ED Keycode = KeyI | altgrMask // 237 í i ACUTE
ISO88591EE Keycode = circumflexBits | KeyI // 238 î i CIRCUMFLEX
ISO88591EF Keycode = diaeresisBits | KeyI // 239 ï i DIAERESIS
ISO88591F0 Keycode = KeyD | altgrMask // 240 ð ETH
ISO88591F1 Keycode = KeyN | altgrMask // 241 ñ n TILDE
ISO88591F2 Keycode = graveAccentBits | KeyO // 242 ò o GRAVE
ISO88591F3 Keycode = KeyO | altgrMask // 243 ó o ACUTE
ISO88591F4 Keycode = circumflexBits | KeyO // 244 ô o CIRCUMFLEX
ISO88591F5 Keycode = tildeBits | KeyO // 245 õ o TILDE
ISO88591F6 Keycode = KeyP | altgrMask // 246 ö o DIAERESIS
ISO88591F7 Keycode = KeyEqual | altgrMask | shiftMask // 247 ÷ DIVISION
ISO88591F8 Keycode = KeyL | altgrMask // 248 ø o STROKE
ISO88591F9 Keycode = graveAccentBits | KeyU // 249 ù u GRAVE
ISO88591FA Keycode = KeyU | altgrMask // 250 ú u ACUTE
ISO88591FB Keycode = circumflexBits | KeyU // 251 û u CIRCUMFLEX
ISO88591FC Keycode = KeyY | altgrMask // 252 ü u DIAERESIS
ISO88591FD Keycode = acuteAccentBits | KeyY // 253 ý y ACUTE
ISO88591FE Keycode = KeyT | altgrMask // 254 þ THORN
ISO88591FF Keycode = diaeresisBits | KeyY // 255 ÿ y DIAERESIS
UNICODE20AC Keycode = Key5 | altgrMask // 20AC € Euro Sign
)
var ascii = [...]Keycode{
ASCII00.mask(), ASCII01.mask(), ASCII02.mask(), ASCII03.mask(),
ASCII04.mask(), ASCII05.mask(), ASCII06.mask(), ASCII07.mask(),
ASCII08.mask(), ASCII09.mask(), ASCII0A.mask(), ASCII0B.mask(),
ASCII0C.mask(), ASCII0D.mask(), ASCII0E.mask(), ASCII0F.mask(),
ASCII10.mask(), ASCII11.mask(), ASCII12.mask(), ASCII13.mask(),
ASCII14.mask(), ASCII15.mask(), ASCII16.mask(), ASCII17.mask(),
ASCII18.mask(), ASCII19.mask(), ASCII1A.mask(), ASCII1B.mask(),
ASCII1C.mask(), ASCII1D.mask(), ASCII1E.mask(), ASCII1F.mask(),
ASCII20.mask(), ASCII21.mask(), ASCII22.mask(), ASCII23.mask(),
ASCII24.mask(), ASCII25.mask(), ASCII26.mask(), ASCII27.mask(),
ASCII28.mask(), ASCII29.mask(), ASCII2A.mask(), ASCII2B.mask(),
ASCII2C.mask(), ASCII2D.mask(), ASCII2E.mask(), ASCII2F.mask(),
ASCII30.mask(), ASCII31.mask(), ASCII32.mask(), ASCII33.mask(),
ASCII34.mask(), ASCII35.mask(), ASCII36.mask(), ASCII37.mask(),
ASCII38.mask(), ASCII39.mask(), ASCII3A.mask(), ASCII3B.mask(),
ASCII3C.mask(), ASCII3D.mask(), ASCII3E.mask(), ASCII3F.mask(),
ASCII40.mask(), ASCII41.mask(), ASCII42.mask(), ASCII43.mask(),
ASCII44.mask(), ASCII45.mask(), ASCII46.mask(), ASCII47.mask(),
ASCII48.mask(), ASCII49.mask(), ASCII4A.mask(), ASCII4B.mask(),
ASCII4C.mask(), ASCII4D.mask(), ASCII4E.mask(), ASCII4F.mask(),
ASCII50.mask(), ASCII51.mask(), ASCII52.mask(), ASCII53.mask(),
ASCII54.mask(), ASCII55.mask(), ASCII56.mask(), ASCII57.mask(),
ASCII58.mask(), ASCII59.mask(), ASCII5A.mask(), ASCII5B.mask(),
ASCII5C.mask(), ASCII5D.mask(), ASCII5E.mask(), ASCII5F.mask(),
ASCII60.mask(), ASCII61.mask(), ASCII62.mask(), ASCII63.mask(),
ASCII64.mask(), ASCII65.mask(), ASCII66.mask(), ASCII67.mask(),
ASCII68.mask(), ASCII69.mask(), ASCII6A.mask(), ASCII6B.mask(),
ASCII6C.mask(), ASCII6D.mask(), ASCII6E.mask(), ASCII6F.mask(),
ASCII70.mask(), ASCII71.mask(), ASCII72.mask(), ASCII73.mask(),
ASCII74.mask(), ASCII75.mask(), ASCII76.mask(), ASCII77.mask(),
ASCII78.mask(), ASCII79.mask(), ASCII7A.mask(), ASCII7B.mask(),
ASCII7C.mask(), ASCII7D.mask(), ASCII7E.mask(), ASCII7F.mask(),
}
var iso88591 = [...]Keycode{
ISO88591A0.mask(), ISO88591A1.mask(), ISO88591A2.mask(), ISO88591A3.mask(),
ISO88591A4.mask(), ISO88591A5.mask(), ISO88591A6.mask(), ISO88591A7.mask(),
ISO88591A8.mask(), ISO88591A9.mask(), ISO88591AA.mask(), ISO88591AB.mask(),
ISO88591AC.mask(), ISO88591AD.mask(), ISO88591AE.mask(), ISO88591AF.mask(),
ISO88591B0.mask(), ISO88591B1.mask(), ISO88591B2.mask(), ISO88591B3.mask(),
ISO88591B4.mask(), ISO88591B5.mask(), ISO88591B6.mask(), ISO88591B7.mask(),
ISO88591B8.mask(), ISO88591B9.mask(), ISO88591BA.mask(), ISO88591BB.mask(),
ISO88591BC.mask(), ISO88591BD.mask(), ISO88591BE.mask(), ISO88591BF.mask(),
ISO88591C0.mask(), ISO88591C1.mask(), ISO88591C2.mask(), ISO88591C3.mask(),
ISO88591C4.mask(), ISO88591C5.mask(), ISO88591C6.mask(), ISO88591C7.mask(),
ISO88591C8.mask(), ISO88591C9.mask(), ISO88591CA.mask(), ISO88591CB.mask(),
ISO88591CC.mask(), ISO88591CD.mask(), ISO88591CE.mask(), ISO88591CF.mask(),
ISO88591D0.mask(), ISO88591D1.mask(), ISO88591D2.mask(), ISO88591D3.mask(),
ISO88591D4.mask(), ISO88591D5.mask(), ISO88591D6.mask(), ISO88591D7.mask(),
ISO88591D8.mask(), ISO88591D9.mask(), ISO88591DA.mask(), ISO88591DB.mask(),
ISO88591DC.mask(), ISO88591DD.mask(), ISO88591DE.mask(), ISO88591DF.mask(),
ISO88591E0.mask(), ISO88591E1.mask(), ISO88591E2.mask(), ISO88591E3.mask(),
ISO88591E4.mask(), ISO88591E5.mask(), ISO88591E6.mask(), ISO88591E7.mask(),
ISO88591E8.mask(), ISO88591E9.mask(), ISO88591EA.mask(), ISO88591EB.mask(),
ISO88591EC.mask(), ISO88591ED.mask(), ISO88591EE.mask(), ISO88591EF.mask(),
ISO88591F0.mask(), ISO88591F1.mask(), ISO88591F2.mask(), ISO88591F3.mask(),
ISO88591F4.mask(), ISO88591F5.mask(), ISO88591F6.mask(), ISO88591F7.mask(),
ISO88591F8.mask(), ISO88591F9.mask(), ISO88591FA.mask(), ISO88591FB.mask(),
ISO88591FC.mask(), ISO88591FD.mask(), ISO88591FE.mask(), ISO88591FF.mask(),
}
+48
View File
@@ -0,0 +1,48 @@
//go:build usb.hid
// +build usb.hid
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")
)
// HID represents a virtual keyboard/mouse/joystick device (with a serial data
// Rx/Tx interface) using the USB HID device class driver.
type HID struct {
// Port is the MCU's native USB core number. If in doubt, leave it
// uninitialized for default (0).
Port int
core *core
}
type HIDConfig struct {
BusSpeed Speed
}
func (hid *HID) Configure(config HIDConfig) error {
c := class{id: classDeviceHID, config: 1}
// verify we have a free USB port and take ownership of it
var st status
hid.core, st = initCore(hid.Port, config.BusSpeed, c)
if !st.ok() {
return ErrHIDInvalidPort
}
return nil
}
func (hid *HID) Ready() bool {
return hid.core.dc.keyboard().ready()
}
func (hid *HID) Keyboard() *Keyboard {
return hid.core.dc.keyboard()
}
+158
View File
@@ -0,0 +1,158 @@
package usb
// Hardware abstraction for USB ports configured as either host or device.
// CoreCount defines the total number of USB cores which may be configured in
// device or host mode.
const CoreCount = descCoreCount
// coreInstance provides statically-allocated instances of each USB core
// configured on this platform.
var coreInstance [CoreCount]core
// core represents the core of a USB port configured as either host or device.
type core struct {
port int
mode int
dc *dcd
hc *hcd
}
// Constant definitions for USB core operating modes.
const (
modeIdle = 0 // USB port has not been configured
modeDevice = 1
modeHost = 2
)
// Speed represents the configured USB data transfer rate, or bus speed, for
// communication between host and device.
type Speed uint8
// Constant definitions for USB data transfer rates. Note that every transfer
// rate may not be supported by every target due to either hardware or software
// limitations. By far, the most commonly-supported rate is USB 1.1 Full-Speed
// (12 Mbit/sec). If unsure, either use FullSpeed or leave it undefined and let
// the driver use the default speed for your target.
const (
LowSpeed Speed = iota + 1 // 1.5 Mbit/sec (USB 1.0)
FullSpeed // 12 Mbit/sec (USB 1.1)
HighSpeed // 480 Mbit/sec (USB 2.0)
SuperSpeed // 5 Gbit/sec (USB 3.0)
DualSuperSpeed // 10 Gbit/sec (USB 3.1, Dual-Lane SS)
)
// initCore initializes a free USB core with given operating mode on the USB
// port at given index, if available. Returns a reference to the initialized
// core or nil if the core is unavailable.
func initCore(port int, speed Speed, class class) (*core, status) {
if port < 0 || port >= CoreCount || 0 == class.config {
return nil, statusInvalid
}
if modeIdle != coreInstance[port].mode {
// Check if requested port is already configured as requested class. If so,
// just return a reference to the existing core instead of an error.
//
// This will allow, for instance, TinyGo examples that try to reconfigure
// the USB (CDC-ACM) UART port (which is already configured by the runtime)
// to continue without error.
if coreInstance[port].mode == class.mode() {
switch class.mode() {
case modeDevice:
if coreInstance[port].dc.class().equals(class) {
return &coreInstance[port], statusOK
}
case modeHost:
if coreInstance[port].hc.class().equals(class) {
return &coreInstance[port], statusOK
}
}
}
return nil, statusBusy
}
switch class.mode() {
case modeDevice:
// Allocate a free device controller and install interrupts
dc, st := initDCD(port, speed, class)
if !st.ok() {
return nil, st
}
// Initialize buffers and device descriptors
if st = dc.init(); !st.ok() {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = modeDevice
coreInstance[port].dc = dc
dc.enable(true) // Enable interrupts and enter runtime
case modeHost:
// Allocate a free host controller and install interrupts
hc, st := initHCD(port, speed, class)
if !st.ok() {
return nil, st
}
// Initialize buffers and device descriptors
if st = hc.init(); !st.ok() {
return nil, st
}
coreInstance[port].port = port
coreInstance[port].mode = modeHost
coreInstance[port].hc = hc
hc.enable(true) // Enable interrupts and enter runtime
default:
return nil, statusInvalid
}
return &coreInstance[port], statusOK
}
// class represents the type of a host/device and its class configuration index.
// The first valid configuration index is 1. Index 0 is reserved and invalid.
type class struct {
id int
config int
}
// Enumerated constants for all supported host/device class configurations.
const (
classDeviceCDC = 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 classDeviceCDC, classDeviceHID:
return modeDevice
default:
return modeIdle
}
}
// equals returns true if and only if all fields of the given class are equal to
// those of the receiver c.
//go:inline
func (c class) equals(class class) bool {
return c.id == class.id && c.config == class.config
}
// status represents the return code of a subroutine.
type status uint8
// Constant definitions for all status codes used within the package.
const (
statusOK status = iota // Success
statusBusy // Busy
statusInvalid // Invalid argument
statusFail // Failure
)
// ok returns true if and only if the receiver st equals statusOK.
//go:inline
func (s status) ok() bool { return statusOK == s }
+341
View File
@@ -0,0 +1,341 @@
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
// at index 0 is the least-significant byte in u and index 7 is the most-
// significant byte.
//go:inline
func leU64(u uint64) []uint8 {
var b [8]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
b[2] = uint8(u >> 16)
b[3] = uint8(u >> 24)
b[4] = uint8(u >> 32)
b[5] = uint8(u >> 40)
b[6] = uint8(u >> 48)
b[7] = uint8(u >> 56)
return b[:]
}
// leU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 3 is the most-
// significant byte.
//go:inline
func leU32(u uint32) []uint8 {
var b [4]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
b[2] = uint8(u >> 16)
b[3] = uint8(u >> 24)
return b[:]
}
// leU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have little-endian ordering; that is, the first element
// at index 0 is the least-significant byte in u and index 1 is the most-
// significant byte.
//go:inline
func leU16(u uint16) []uint8 {
var b [2]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[0] = uint8(u)
b[1] = uint8(u >> 8)
return b[:]
}
// beU64 returns a slice containing 8 bytes from the given uint64 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 7 is the least-
// significant byte.
//go:inline
func beU64(u uint64) []uint8 {
var b [8]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[7] = uint8(u)
b[6] = uint8(u >> 8)
b[5] = uint8(u >> 16)
b[4] = uint8(u >> 24)
b[3] = uint8(u >> 32)
b[2] = uint8(u >> 40)
b[1] = uint8(u >> 48)
b[0] = uint8(u >> 56)
return b[:]
}
// beU32 returns a slice containing 4 bytes from the given uint32 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 3 is the least-
// significant byte.
//go:inline
func beU32(u uint32) []uint8 {
var b [4]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[3] = uint8(u)
b[2] = uint8(u >> 8)
b[1] = uint8(u >> 16)
b[0] = uint8(u >> 24)
return b[:]
}
// beU16 returns a slice containing 2 bytes from the given uint16 u.
//
// The returned bytes have big-endian ordering; that is, the first element at
// index 0 is the most-significant byte in u and index 1 is the least-
// significant byte.
//go:inline
func beU16(u uint16) []uint8 {
var b [2]uint8
if u == 0 {
// skip all processing for the common case (u = 0)
return b[:]
}
b[1] = uint8(u)
b[0] = uint8(u >> 8)
return b[:]
}
// revU64 returns the given uint64 u with bytes in the reverse order.
//go:inline
func revU64(u uint64) uint64 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00000000000000FF) << 56) |
((u & 0x000000000000FF00) << 40) |
((u & 0x0000000000FF0000) << 24) |
((u & 0x00000000FF000000) << 8) |
((u & 0x000000FF00000000) >> 8) |
((u & 0x0000FF0000000000) >> 24) |
((u & 0x00FF000000000000) >> 40) |
((u & 0xFF00000000000000) >> 56)
}
// revU32 returns the given uint32 u with bytes in the reverse order.
//go:inline
func revU32(u uint32) uint32 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x000000FF) << 24) | ((u & 0x0000FF00) << 8) |
((u & 0x00FF0000) >> 8) | ((u & 0xFF000000) >> 24)
}
// revU16 returns the given uint16 u with bytes in the reverse order.
//go:inline
func revU16(u uint16) uint16 {
if u == 0 {
// skip all processing for the common case (u = 0)
return 0
}
return ((u & 0x00FF) << 8) | ((u & 0xFF00) >> 8)
}
// packU64 returns a uint64 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 7, if given. If fewer
// than 8 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU64(b []uint8) (u uint64) {
for i := 0; i < 8 && i < len(b); i++ {
u |= uint64(b[i]) << (i * 8)
}
return
}
// packU32 returns a uint32 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 3, if given. If fewer
// than 4 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU32(b []uint8) (u uint32) {
for i := 0; i < 4 && i < len(b); i++ {
u |= uint32(b[i]) << (i * 8)
}
return
}
// packU16 returns a uint16 constructed by concatenating the bytes in slice b.
//
// The least-significant byte in the returned value is the first element at
// index 0 in b and the most significant byte is index 1, if given. If fewer
// than 2 elements are given in b, the corresponding bytes in the returned value
// are all 0.
//go:inline
func packU16(b []uint8) (u uint16) {
for i := 0; i < 2 && i < len(b); i++ {
u |= uint16(b[i]) << (i * 8)
}
return
}
// msU8 returns the most-significant byte of u.
//go:inline
func msU8(u uint16) uint8 { return uint8(u >> 8) }
// lsU8 returns the least-significant byte of u.
//go:inline
func lsU8(u uint16) uint8 { return uint8(u) }
// cycles converts the given number of microseconds to CPU cycles for a CPU with
// given frequency.
//go:inline
func cycles(microsec, cpuFreqHz uint32) uint32 {
return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000)
}
//go:inline
func endpointValid(address uint8) bool {
return address&descEndpointInvalid == 0
}
//go:inline
func unpackEndpoint(address uint8) (number, direction uint8) {
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos,
(address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
}
//go:inline
func packEndpoint(number, direction uint8) (address uint8) {
return ((number << descEndptAddrNumberPos) & descEndptAddrNumberMsk) |
((direction << descEndptAddrDirectionPos) & descEndptAddrDirectionMsk)
}
//go:inline
func endpointNumber(address uint8) (number uint8) {
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos
}
//go:inline
func endpointDirection(address uint8) (direction uint8) {
return (address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
}
//go:inline
func rxEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionOut
}
//go:inline
func txEndpoint(number uint8) uint8 {
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionIn
}
//go:inline
func endpointIndex(address uint8) uint8 {
return ((address & descEndptAddrNumberMsk) << 1) |
((address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos)
}
//go:inline
func indexEndpoint(index uint8) uint8 {
return ((index >> 1) & descEndptAddrNumberMsk) |
((index & 0x1) << descEndptAddrDirectionPos)
}
// wrap computes the index into a circular buffer of length mod by walking
// forward n elements if n is positive, or reverse -n elements if n is negative.
// For example, both wrap(12, 10) and wrap(-18, 10) return 2.
//go:inline
func wrap(n, mod int) int {
if mod <= 0 {
// Buffer length (mod) must be positive.
return 0
}
if n < 0 {
if -n < mod {
// Do not wrap around (no underflow).
return mod + n
}
return mod - (-n % mod)
}
if n < mod {
// Do not wrap around (no overflow).
return n
}
return n % mod
}
// 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
}
+24
View File
@@ -0,0 +1,24 @@
// +build arm
package usb
import "device/arm"
// udelay waits for the given number of microseconds before returning.
// We cannot use the sleep timer from this context (import cycle), but we need
// an approximate method to spin CPU cycles for short periods of time.
//go:inline
func udelay(microsec uint32) {
n := cycles(microsec, descCPUFrequencyHz)
for i := uint32(0); i < n; i++ {
arm.Asm(`nop`)
}
}
func disableInterrupts() uintptr {
return arm.DisableInterrupts()
}
func enableInterrupts(mask uintptr) {
arm.EnableInterrupts(mask)
}
+8 -6
View File
@@ -25,14 +25,16 @@ func init() {
initClocks()
initRTC()
initSERCOMClocks()
initUSBClock()
initADCClock()
// connect to USB CDC interface
machine.Serial.Configure(machine.UARTConfig{})
if !machine.USB.Configured() {
machine.USB.Configure(machine.UARTConfig{})
}
//// connect to USB CDC interface
//machine.Serial.Configure(usb.UARTConfig{})
//if !machine.USB.Configured() {
// machine.USB.Configure(usb.UARTConfig{})
//}
machine.InitUSB()
machine.InitSerial()
}
func putchar(c byte) {
@@ -36,7 +36,7 @@ func handleHardFault(sp *interruptStack) {
if fault.Mem().WhileUnstackingException() {
print(" while unstacking exception")
}
if fault.Mem().WileStackingException() {
if fault.Mem().WhileStackingException() {
print(" while stacking exception")
}
if fault.Mem().DuringFPLazyStatePres() {
@@ -162,13 +162,13 @@ func (fs MemFaultStatus) WhileUnstackingException() bool {
return fs&arm.SCB_CFSR_MUNSTKERR != 0
}
// WileStackingException: stacking for an exception entry has caused one or more
// WhileStackingException: stacking for an exception entry has caused one or more
// access violations
//
// "When this bit is 1, the SP is still adjusted but the values in the context
// area on the stack might be incorrect. The processor has not written a fault
// address to the MMAR."
func (fs MemFaultStatus) WileStackingException() bool {
func (fs MemFaultStatus) WhileStackingException() bool {
return fs&arm.SCB_CFSR_MSTKERR != 0
}
+9 -2
View File
@@ -7,6 +7,7 @@ import (
"device/arm"
"device/nxp"
"machine"
"machine/usb"
"math/bits"
"unsafe"
)
@@ -35,7 +36,7 @@ func main() {
// initialize cache and MPU
initCache()
// enable SysTick, GPIO, and peripherals
// enable SysTick, GPIO, USB, and other peripherals
initPeripherals()
// reenable interrupts
@@ -107,7 +108,8 @@ func initPeripherals() {
initPins() // configure GPIO
enablePeripheralClocks() // activate peripheral clock gates
initUART() // configure UART (initialized first for debugging)
initUSB() // configure USB CDC-ACM (UART0)
initUART() // configure hardware UART (UART1)
}
func initPins() {
@@ -122,6 +124,11 @@ func initUART() {
machine.Serial.Configure(machine.UARTConfig{})
}
func initUSB() {
// machine.HID0.Configure(usb.HIDConfig{})
machine.UART0.Configure(usb.UARTConfig{})
}
func putchar(c byte) {
machine.Serial.WriteByte(c)
}
+52 -34
View File
@@ -36,15 +36,31 @@ var (
Denominator: 1, // 30-bit DENOM of fractional loop divider
Src: 0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
}
Usb1PllConfig = nxp.ClockConfigUsbPll{
Instance: 1, // USB PLL instance
LoopDivider: 0, // PLL loop divider, Fout=Fin*20
Src: 0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
Usb1PhyConfig = nxp.ClockConfigUsbPhy{
Instance: 1, // USB PHY number (1 or 2)
XtalFreq: OSC_FREQ, // External reference clock frequency (Hz)
DCal: 0xC, // Decode to trim nominal 17.78mA current source
TxCal45DP: 0x6, // Decode to trim nominal 45-Ohm series Rp on USB D+
TxCal45DM: 0x6, // Decode to trim nominal 45-Ohm series Rp on USB D-
PllConfig: nxp.ClockConfigUsbPll{
Instance: 1, // USB PLL number (1 or 2)
LoopDivider: 0, // PLL loop divider (0 [Fout=Fref*20] or 1 [Fout=Fref*22])
Src: 0, // PLL bypass clock source (0 [OSC24M] or 1 [CLK1_P & CLK1_N])
Pfd: nil, // Phase fractional divisors (len=4, or nil for boot default)
},
}
Usb2PllConfig = nxp.ClockConfigUsbPll{
Instance: 2, // USB PLL instance
LoopDivider: 0, // PLL loop divider, Fout=Fin*20
Src: 0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
Usb2PhyConfig = nxp.ClockConfigUsbPhy{
Instance: 2, // USB PHY number (1 or 2)
XtalFreq: OSC_FREQ, // External reference clock frequency (Hz)
DCal: 0xC, // Decode to trim the nominal 17.78mA current source
TxCal45DP: 0x6, // Decode to trim the nominal 45-Ohm series Rp on USB D+
TxCal45DM: 0x6, // Decode to trim the nominal 45-Ohm series Rp on USB D-
PllConfig: nxp.ClockConfigUsbPll{
Instance: 2, // USB PLL number (1 or 2)
LoopDivider: 0, // PLL loop divider (0 [Fout=Fref*20] or 1 [Fout=Fref*22])
Src: 0, // PLL bypass clock source (0 [OSC24M] or 1 [CLK1_P & CLK1_N])
Pfd: nil, // Phase fractional divisors (len=4, or nil for boot default)
},
}
)
@@ -86,7 +102,7 @@ func initClocks() {
// set VDD_SOC to 1.275V, necessary to config AHB to 600 MHz
nxp.DCDC.REG3.Set((nxp.DCDC.REG3.Get() & ^uint32(nxp.DCDC_REG3_TRG_Msk)) |
((13 << nxp.DCDC_REG3_TRG_Pos) & nxp.DCDC_REG3_TRG_Msk))
((0x13 << nxp.DCDC_REG3_TRG_Pos) & nxp.DCDC_REG3_TRG_Msk))
// wait until DCDC_STS_DC_OK bit is asserted
for !nxp.DCDC.REG0.HasBits(nxp.DCDC_REG0_STS_DC_OK_Msk) {
@@ -105,6 +121,8 @@ func initClocks() {
nxp.DivIpArm.Div(1) // divide ARM_PODF (DIV2)
nxp.DivIpPeriphClk2.Div(0) // divide PERIPH_CLK2_PODF (DIV1)
nxp.ClockIpUsbOh3.Enable(false) // disable USB
nxp.ClockIpGpt1.Enable(false) // disable GPT/PIT
nxp.ClockIpGpt1S.Enable(false) //
nxp.ClockIpGpt2.Enable(false) //
@@ -113,6 +131,11 @@ func initClocks() {
nxp.DivIpPerclk.Div(0) // divide PERCLK_PODF (DIV1)
nxp.ClockIpGpio1.Enable(false) // disable GPIO
nxp.ClockIpGpio2.Enable(false) //
nxp.ClockIpGpio3.Enable(false) //
nxp.ClockIpGpio4.Enable(false) //
nxp.ClockIpUsdhc1.Enable(false) // disable USDHC1
nxp.DivIpUsdhc1.Div(1) // divide USDHC1_PODF (DIV2)
nxp.MuxIpUsdhc1.Mux(1) // USDHC1 select PLL2_PFD0
@@ -121,9 +144,9 @@ func initClocks() {
nxp.MuxIpUsdhc2.Mux(1) // USDHC2 select PLL2_PFD0
nxp.ClockIpSemc.Enable(false) // disable SEMC
nxp.DivIpSemc.Div(1) // divide SEMC_PODF (DIV2)
nxp.DivIpSemc.Div(7) // divide SEMC_PODF (DIV8)
nxp.MuxIpSemcAlt.Mux(0) // SEMC_ALT select PLL2_PFD2
nxp.MuxIpSemc.Mux(1) // SEMC select SEMC_ALT
nxp.MuxIpSemc.Mux(0) // SEMC select PERIPH_CLK
if false {
// TODO: external flash is on this bus, configured via DCD block
@@ -192,7 +215,7 @@ func initClocks() {
nxp.ClockIpLcdPixel.Enable(false) // disable LCDIF
nxp.DivIpLcdifPre.Div(1) // divide LCDIF_PRED (DIV2)
nxp.DivIpLcdif.Div(3) // divide LCDIF_CLK_PODF (DIV4)
nxp.MuxIpLcdifPre.Mux(5) // LCDIF_PRE select PLL3_PFD1
nxp.MuxIpLcdifPre.Mux(4) // LCDIF_PRE select PLL2_PFD1
nxp.ClockIpSpdif.Enable(false) // disable SPDIF
nxp.DivIpSpdif0Pre.Div(1) // divide SPDIF0_CLK_PRED (DIV2)
@@ -210,43 +233,43 @@ func initClocks() {
nxp.MuxIpPll3Sw.Mux(0) // PLL3_SW select PLL3_MAIN
// Disable Audio/Video/Ethernet PLLs
nxp.CCM_ANALOG.PLL_AUDIO.Set(nxp.CCM_ANALOG_PLL_AUDIO_POWERDOWN_Msk)
nxp.CCM_ANALOG.PLL_VIDEO.Set(nxp.CCM_ANALOG_PLL_VIDEO_POWERDOWN_Msk)
nxp.CCM_ANALOG.PLL_ENET.Set(nxp.CCM_ANALOG_PLL_ENET_POWERDOWN_Msk)
ArmPllConfig.Configure() // init ARM PLL
// SYS PLL (PLL2) @ 528 MHz
// PFD0 = 396 MHz -> USDHC1/USDHC2(DIV2)=198 MHz
// PFD1 = 594 MHz -> (currently unused)
// PFD2 = 327.72 MHz -> SEMC(DIV2)=163.86 MHz, FlexSPI/FlexSPI2=327.72 MHz
// PFD3 = 454.73 MHz -> (currently unused)
// PFD2 = 327.72 MHz -> FlexSPI/FlexSPI2=327.72 MHz
// PFD3 = 594 MHz -> (currently unused)
SysPllConfig.Configure(24, 16, 29, 16) // init SYS PLL and PFDs
// USB1 PLL (PLL3) @ 480 MHz
// PFD0 -> (currently unused)
// PFD1 -> (currently unused)
// PFD2 -> (currently unused)
// PFD3 -> (currently unused)
Usb1PllConfig.Configure() // init USB1 PLL and PFDs
Usb2PllConfig.Configure() // init USB2 PLL
Usb1PhyConfig.Configure() // init USB1 HS PHY/PLL
Usb2PhyConfig.Configure() // init USB2 HS PHY/PLL
nxp.MuxIpPrePeriph.Mux(3) // PRE_PERIPH select ARM_PLL
nxp.MuxIpPeriph.Mux(0) // PERIPH select PRE_PERIPH
nxp.MuxIpPeriphClk2.Mux(1) // PERIPH_CLK2 select OSC
nxp.MuxIpPerclk.Mux(1) // PERCLK select OSC
// set LVDS1 clock source
// set LVDS1 clock source (ARM_PLL)
nxp.CCM_ANALOG.MISC1.Set((nxp.CCM_ANALOG.MISC1.Get() & ^uint32(nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Msk)) |
((0 << nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Pos) & nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Msk))
// set CLOCK_OUT1 divider
// set CLOCK_OUT1 divider (DIV1)
nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO1_DIV_Msk)) |
((0 << nxp.CCM_CCOSR_CLKO1_DIV_Pos) & nxp.CCM_CCOSR_CLKO1_DIV_Msk))
// set CLOCK_OUT1 source
// set CLOCK_OUT1 source (PLL2/DIV2)
nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO1_SEL_Msk)) |
((1 << nxp.CCM_CCOSR_CLKO1_SEL_Pos) & nxp.CCM_CCOSR_CLKO1_SEL_Msk))
// set CLOCK_OUT2 divider
// set CLOCK_OUT2 divider (DIV1)
nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO2_DIV_Msk)) |
((0 << nxp.CCM_CCOSR_CLKO2_DIV_Pos) & nxp.CCM_CCOSR_CLKO2_DIV_Msk))
// set CLOCK_OUT2 source
// set CLOCK_OUT2 source (SPDIF0)
nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO2_SEL_Msk)) |
((18 << nxp.CCM_CCOSR_CLKO2_SEL_Pos) & nxp.CCM_CCOSR_CLKO2_SEL_Msk))
((29 << nxp.CCM_CCOSR_CLKO2_SEL_Pos) & nxp.CCM_CCOSR_CLKO2_SEL_Msk))
nxp.CCM.CCOSR.ClearBits(nxp.CCM_CCOSR_CLK_OUT_SEL_Msk) // set CLK_OUT1 drives CLK_OUT
nxp.CCM.CCOSR.SetBits(nxp.CCM_CCOSR_CLKO1_EN_Msk) // enable CLK_OUT1
@@ -254,15 +277,10 @@ func initClocks() {
nxp.ClockIpIomuxcGpr.Enable(false) // disable IOMUXC_GPR
nxp.ClockIpIomuxc.Enable(false) // disable IOMUXC
// set GPT1 High frequency reference clock source
// set GPT1 High frequency reference clock source (PERCLK)
nxp.IOMUXC_GPR.GPR5.ClearBits(nxp.IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_Msk)
// set GPT2 High frequency reference clock source
// set GPT2 High frequency reference clock source (PERCLK)
nxp.IOMUXC_GPR.GPR5.ClearBits(nxp.IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_Msk)
nxp.ClockIpGpio1.Enable(false) // disable GPIO
nxp.ClockIpGpio2.Enable(false) //
nxp.ClockIpGpio3.Enable(false) //
nxp.ClockIpGpio4.Enable(false) //
}
func enableTimerClocks() {
+1 -1
View File
@@ -142,7 +142,7 @@ func timerSleep(cycles uint32) bool {
nxp.PIT.TIMER[pitSleepTimer].TCTRL.Set(nxp.PIT_TIMER_TCTRL_TIE) // enable interrupts
nxp.PIT.TIMER[pitSleepTimer].TCTRL.SetBits(nxp.PIT_TIMER_TCTRL_TEN) // start timer
for {
//arm.Asm("wfi") // TODO: causes hardfault! why?
waitForEvents()
if pitActive.Get() == 0 {
return true
}