mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 11:07:46 +00:00
refactor USB package with device class build tags
added basic HID keyboard support for SAMx51 (not fully-functional)
This commit is contained in:
@@ -6,10 +6,13 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var keyboard = machine.HID0.Keyboard()
|
||||
var keyboard = machine.USB.Keyboard()
|
||||
|
||||
func main() {
|
||||
|
||||
for !machine.USB.Ready() {
|
||||
}
|
||||
|
||||
println("USB HID keyboard demo")
|
||||
|
||||
for {
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
// Digital pins
|
||||
const (
|
||||
// = Pin Alt. Function SERCOM PWM Timer Interrupt
|
||||
@@ -252,8 +248,6 @@ const (
|
||||
RESET_MAGIC_VALUE = 0xF01669EF // Used to reset into bootloader
|
||||
)
|
||||
|
||||
var USB = usb.UART{Port: 0}
|
||||
|
||||
// USB CDC pins
|
||||
const (
|
||||
USBCDC_HOSTEN_PIN = D77 // (PA27) host enable
|
||||
|
||||
@@ -5,11 +5,3 @@ package machine
|
||||
|
||||
// Serial is implemented via USB (USB-CDC).
|
||||
var Serial = USB
|
||||
|
||||
func init() {
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build baremetal && usb.cdc
|
||||
// +build baremetal,usb.cdc
|
||||
|
||||
package machine
|
||||
|
||||
import "machine/usb"
|
||||
|
||||
var USB = &usb.CDC{Port: 0}
|
||||
|
||||
func init() {
|
||||
// Configure USB D+/D- pins.
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,usb.hid
|
||||
|
||||
package machine
|
||||
|
||||
import "machine/usb"
|
||||
|
||||
var USB = &usb.HID{Port: 0}
|
||||
|
||||
func init() {
|
||||
// Configure USB D+/D- pins.
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
//go:build baremetal && usb.cdc
|
||||
// +build baremetal,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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,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
|
||||
}
|
||||
}
|
||||
+11
-664
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
// dcdCount defines the number of USB cores to configure for device mode. It is
|
||||
// computed as the sum of all declared device configuration descriptors.
|
||||
const dcdCount = descCDCACMCount + descHIDCount
|
||||
const dcdCount = descCDCCount + descHIDCount
|
||||
|
||||
// dcdInstance provides statically-allocated instances of each USB device
|
||||
// controller configured on this platform.
|
||||
@@ -44,8 +44,8 @@ func initDCD(port int, speed Speed, class class) (*dcd, status) {
|
||||
return nil, statusInvalid // Must have defined device controllers
|
||||
}
|
||||
switch class.id {
|
||||
case classDeviceCDCACM:
|
||||
if 0 == class.config || class.config > descCDCACMCount {
|
||||
case classDeviceCDC:
|
||||
if 0 == class.config || class.config > descCDCCount {
|
||||
return nil, statusInvalid // Must have defined descriptors
|
||||
}
|
||||
default:
|
||||
@@ -319,26 +319,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
d.cc.config = 1
|
||||
}
|
||||
d.event(dcdEvent{id: dcdEventDeviceConfiguration})
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.uartConfigure()
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.serialConfigure()
|
||||
d.keyboardConfigure()
|
||||
d.mouseConfigure()
|
||||
d.joystickConfigure()
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
d.controlSetConfiguration()
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
@@ -360,23 +342,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descRequestStandardGetDescriptor:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
d.controlGetDescriptor(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
// GET CONFIGURATION (0x08):
|
||||
case descRequestStandardGetConfiguration:
|
||||
@@ -393,47 +360,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// --- INTERFACE Tx (IN) ---
|
||||
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
|
||||
|
||||
// Identify which request was received
|
||||
switch sup.bRequest {
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descRequestStandardGetDescriptor:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// GET HID REPORT (0x01):
|
||||
case descHIDRequestGetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
if d.controlGetInterfaceDescriptor(sup) {
|
||||
return dcdStageDataIn
|
||||
}
|
||||
|
||||
// --- ENDPOINT Rx (OUT) ---
|
||||
@@ -486,158 +414,8 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// === CLASS REQUEST ===
|
||||
case descRequestTypeTypeClass:
|
||||
|
||||
// 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:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
// line coding must contain exactly 7 bytes
|
||||
if uint16(descCDCACMLineCodingSize) == sup.wLength {
|
||||
d.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
||||
uint32(descCDCACMLineCodingSize), true)
|
||||
// CDC Line Coding packet receipt handling occurs in method
|
||||
// controlComplete().
|
||||
return dcdStageDataOut
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// CDC | SET CONTROL LINE STATE (0x22):
|
||||
case descCDCRequestSetControlLineState:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch sup.wIndex {
|
||||
|
||||
// Control/status interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
// CDC Control Line State packet receipt handling occurs in method
|
||||
// controlComplete().
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// CDC | SEND BREAK (0x23):
|
||||
case descCDCRequestSendBreak:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET REPORT (0x09)
|
||||
case descHIDRequestSetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if sup.wLength <= 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
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET IDLE (0x0A)
|
||||
case descHIDRequestSetIdle:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
idleRate := sup.wValue >> 8
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_ = idleRate
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
|
||||
// --- INTERFACE Tx (IN) ---
|
||||
case descRequestTypeRecipientInterface | descRequestTypeDirIn:
|
||||
|
||||
// Identify which request was received
|
||||
switch sup.bRequest {
|
||||
|
||||
// HID | GET REPORT (0x01)
|
||||
case descHIDRequestGetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
reportType := uint8(sup.wValue >> 8)
|
||||
reportID := uint8(sup.wValue)
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_, _ = reportType, reportID
|
||||
d.controlTransmit(
|
||||
d.controlStatusBuffer([]uint8{0, 0}),
|
||||
2, false)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request recepient or direction
|
||||
}
|
||||
// Forward all class requests to the device class implementation.
|
||||
return d.controlClassRequest(sup)
|
||||
|
||||
case descRequestTypeTypeVendor:
|
||||
default:
|
||||
@@ -648,434 +426,3 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// was invalid or unhandled. Stall the endpoint.
|
||||
return dcdStageStall
|
||||
}
|
||||
|
||||
// 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:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch d.setup.wIndex {
|
||||
|
||||
// CDC-ACM Control Interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
// Notify PHY to handle triggers like special baud rates, which
|
||||
// signal to reboot into bootloader or begin receiving OTA updates
|
||||
d.uartSetLineCoding(acm.cx[:])
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// CDC | SET CONTROL LINE STATE (0x22):
|
||||
case descCDCRequestSetControlLineState:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch d.setup.wIndex {
|
||||
|
||||
// Control/status interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
|
||||
d.uartSetLineState(d.setup.wValue)
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
// HID | SET REPORT (0x09)
|
||||
case descHIDRequestSetReport:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
// Determine interface destination of the request
|
||||
switch d.setup.wIndex {
|
||||
|
||||
// HID Keyboard Interface
|
||||
case descHIDInterfaceKeyboard:
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch d.setup.wValue >> 8 {
|
||||
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
if 1 == d.setup.wLength {
|
||||
hid.keyboard.led = hid.cx[0]
|
||||
d.controlTransmit(uintptr(0), 0, false)
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
// HID Serial Interface
|
||||
case descHIDInterfaceSerial:
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch d.setup.wValue >> 8 {
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if d.setup.wLength >= 4 && 0x68C245A9 == packU32(hid.cx[0:4]) {
|
||||
d.enableSOF(true, descHIDInterfaceCount)
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled recepient or direction
|
||||
}
|
||||
|
||||
default:
|
||||
// Unhandled request type
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dcd) controlDescriptorCDCACM(sup dcdSetup) {
|
||||
|
||||
acm := &descCDCACM[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(descCDCACMConfigSize)
|
||||
_ = copy(acm.dx[:], acm.config[:dxn])
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if 0 == len(acm.locale) {
|
||||
break // No string descriptors defined!
|
||||
}
|
||||
var sd []uint8
|
||||
if 0 == uint8(sup.wValue) {
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dcd) controlDescriptorHID(sup dcdSetup) {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
dxn := uint8(0)
|
||||
pos := uint8(0)
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
switch sup.wValue >> 8 {
|
||||
|
||||
// Device descriptor
|
||||
case descTypeDevice:
|
||||
dxn = descLengthDevice
|
||||
_ = copy(hid.dx[:], hid.device[:dxn])
|
||||
|
||||
// Configuration descriptor
|
||||
case descTypeConfigure:
|
||||
dxn = uint8(descHIDConfigSize)
|
||||
_ = copy(hid.dx[:], hid.config[:dxn])
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
if 0 == len(hid.locale) {
|
||||
break // No string descriptors defined!
|
||||
}
|
||||
var sd []uint8
|
||||
if 0 == uint8(sup.wValue) {
|
||||
|
||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||
// strings in some given language. This case (setup.wValue = [0x03]00)
|
||||
// is a string request from the host to determine what that language is.
|
||||
//
|
||||
// In subsequent string requests, the host will populate setup.wIndex
|
||||
// with the language code we return here in this string descriptor.
|
||||
//
|
||||
// This way all strings returned to the host are in the same language,
|
||||
// whatever language that may be.
|
||||
code := int(sup.wIndex)
|
||||
if code >= len(hid.locale) {
|
||||
code = 0
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
//go:build baremetal && usb.cdc
|
||||
// +build baremetal,usb.cdc
|
||||
|
||||
package usb
|
||||
|
||||
// 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
|
||||
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)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
},
|
||||
qualif: &[descLengthQualification]uint8{
|
||||
descLengthQualification, // Size of this descriptor in bytes
|
||||
descTypeQualification, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
0, // Reserved
|
||||
},
|
||||
config: &[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)
|
||||
|
||||
// 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
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
//go:build baremetal && usb.cdc && (atsamd51 || atsame5x)
|
||||
// +build baremetal
|
||||
// +build usb.cdc
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package usb
|
||||
|
||||
import "runtime/volatile"
|
||||
|
||||
// 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,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,usb.hid
|
||||
|
||||
package usb
|
||||
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
//go:build baremetal && usb.hid && (atsamd51 || atsame5x)
|
||||
// +build baremetal
|
||||
// +build usb.hid
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package usb
|
||||
|
||||
// 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,
|
||||
},
|
||||
}
|
||||
+3
-933
@@ -1,7 +1,5 @@
|
||||
package usb
|
||||
|
||||
import "runtime/volatile"
|
||||
|
||||
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
|
||||
|
||||
const descLanguageEnglish = uint16(0x0409) // (US) English
|
||||
@@ -137,6 +135,9 @@ const (
|
||||
descDeviceCapExtAttrBESLPos = 2
|
||||
)
|
||||
|
||||
// descEndpointInvalid represents an invalid endpoint address.
|
||||
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
|
||||
|
||||
const (
|
||||
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
|
||||
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
|
||||
@@ -184,222 +185,6 @@ const (
|
||||
descEndptConfigAttrTxInterrupt = (descEndptAttrSyncTypeSync | descEndptConfigAttr) << descEndptConfigAttrTxPos
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// 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 CDC-ACM configuration descriptors.
|
||||
descCDCACMConfigSize = uint16(
|
||||
descLengthConfigure + // Configuration Header
|
||||
descLengthInterface + // CDC Interface Descriptor
|
||||
descCDCFuncLengthHeader + // CDC Header
|
||||
descCDCFuncLengthCallManagement + // CDC Call Management Func Descriptor
|
||||
descCDCFuncLengthAbstractControl + // CDC Abstract Control Func Descriptor
|
||||
descCDCFuncLengthUnion + // CDC Union Functional Descriptor
|
||||
descLengthEndpoint + // CDC Status IN Endpoint Descriptor
|
||||
descLengthInterface + // CDC Data Interface Descriptor
|
||||
descLengthEndpoint + // CDC Data IN Endpoint Descriptor
|
||||
descLengthEndpoint) // CDC Data OUT Endpoint Descriptor
|
||||
|
||||
// Size of all HID configuration descriptors.
|
||||
descHIDConfigSize = uint16(
|
||||
descLengthConfigure + // Configuration Header
|
||||
descLengthInterface + // Keyboard Interface Descriptor
|
||||
descLengthInterface + // Keyboard HID Interface Descriptor
|
||||
descLengthEndpoint + // Keyboard Endpoint Descriptor
|
||||
descLengthInterface + // Mouse Interface Descriptor
|
||||
descLengthInterface + // Mouse HID Interface Descriptor
|
||||
descLengthEndpoint + // Mouse Endpoint Descriptor
|
||||
descLengthInterface + // Serial Interface Descriptor
|
||||
descLengthInterface + // Serial HID Interface Descriptor
|
||||
descLengthEndpoint + // Serial 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
|
||||
)
|
||||
|
||||
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
|
||||
@@ -428,718 +213,3 @@ const (
|
||||
// anyone other than TinyGo devs; 64*4 = 256 B (i.e., 31 UTF-16 code points
|
||||
// for each string) seems a good compromise.
|
||||
)
|
||||
|
||||
// descEndpointInvalid represents an invalid endpoint address.
|
||||
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
|
||||
|
||||
// descCDCACMLineCodingSize 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, descCDCACMLineCodingSize defines the number of bytes
|
||||
// that are transferred following a control SETUP request.
|
||||
const descCDCACMLineCodingSize = 7
|
||||
|
||||
// descCDCACMLineCoding represents an emulated UART's line configuration.
|
||||
//
|
||||
// Use descCDCACMLineCodingSize instead of unsafe.Sizeof(descCDCACMLineCoding)
|
||||
// in any transfer requests, because the actual struct is padded for alignment.
|
||||
type descCDCACMLineCoding struct {
|
||||
baud uint32
|
||||
stopBits uint8
|
||||
parity uint8
|
||||
numBits uint8
|
||||
_ uint8
|
||||
}
|
||||
|
||||
// parse initializes the receiver descCDCACMLineCoding 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 *descCDCACMLineCoding) parse(v []uint8) bool {
|
||||
if len(v) >= descCDCACMLineCodingSize {
|
||||
s.baud = packU32(v[:])
|
||||
s.stopBits = v[4]
|
||||
s.parity = v[5]
|
||||
s.numBits = v[6]
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// descCDCACMLineState represents an emulated UART's line state.
|
||||
type descCDCACMLineState 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 descCDCACMLineState 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 *descCDCACMLineState) parse(v uint16) bool {
|
||||
s.dataTerminalReady = 0 != v&0x1
|
||||
s.requestToSend = 0 != v&0x2
|
||||
return true
|
||||
}
|
||||
|
||||
type descCDCACMState uint8
|
||||
|
||||
const (
|
||||
descCDCACMStateConfigured descCDCACMState = iota // Received SET_CONFIGURATION class request
|
||||
descCDCACMStateLineState // Received SET_LINE_STATE after Configured state
|
||||
descCDCACMStateLineCoding // Received SET_LINE_CODING after LineState state
|
||||
)
|
||||
|
||||
func (s *descCDCACMState) set(state descCDCACMState) {
|
||||
if state > *s {
|
||||
// state must be incremented in-order. Otherwise, reset to initial state.
|
||||
if state == *s+1 {
|
||||
*s = state
|
||||
} else {
|
||||
var init descCDCACMState // Reset to zero-value of type.
|
||||
*s = init
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Common configuration constants for the USB CDC-ACM (single) device class.
|
||||
const (
|
||||
descCDCACMLanguageCount = 1 // String descriptor languages available
|
||||
|
||||
descCDCACMInterfaceCount = 2 // Interfaces for all CDC-ACM configurations.
|
||||
descCDCACMEndpointCount = 4 // Endpoints for all CDC-ACM configurations.
|
||||
|
||||
descCDCACMEndpointCtrl = 0 // CDC-ACM Control Endpoint 0
|
||||
|
||||
descCDCACMInterfaceCtrl = 0 // CDC-ACM Control Interface
|
||||
descCDCACMEndpointStatus = 1 // CDC-ACM Interrupt IN Endpoint
|
||||
descCDCACMConfigAttrStatus = descEndptConfigAttrRxUnused | descEndptConfigAttrTxInterrupt
|
||||
|
||||
descCDCACMInterfaceData = 1 // CDC-ACM Data Interface
|
||||
descCDCACMEndpointDataRx = 2 // CDC-ACM Bulk Data OUT (Rx) Endpoint
|
||||
descCDCACMConfigAttrDataRx = descEndptConfigAttrRxBulk | descEndptConfigAttrTxUnused
|
||||
descCDCACMEndpointDataTx = 3 // CDC-ACM Bulk Data IN (Tx) Endpoint
|
||||
descCDCACMConfigAttrDataTx = descEndptConfigAttrRxUnused | descEndptConfigAttrTxBulk
|
||||
)
|
||||
|
||||
// descCDCACMClass holds references to all descriptors, buffers, and control
|
||||
// structures for the USB CDC-ACM (single) device class.
|
||||
type descCDCACMClass struct {
|
||||
*descCDCACMClassData // Target-defined, class-specific data
|
||||
|
||||
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
|
||||
device *[descLengthDevice]uint8 // device descriptor
|
||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||
config *[descCDCACMConfigSize]uint8 // configuration descriptor
|
||||
|
||||
state volatile.Register8
|
||||
}
|
||||
|
||||
func (c *descCDCACMClass) setState(state descCDCACMState) {
|
||||
s := descCDCACMState(c.state.Get())
|
||||
s.set(state)
|
||||
c.state.Set(uint8(s))
|
||||
}
|
||||
|
||||
// descCDCACM holds statically-allocated instances for each of the CDC-ACM
|
||||
// (single) device class configurations, ordered by index (offset by -1).
|
||||
var descCDCACM = [dcdCount]descCDCACMClass{
|
||||
|
||||
{ // CDC-ACM (single) class configuration index 1
|
||||
descCDCACMClassData: &descCDCACMData[0],
|
||||
|
||||
locale: &[descCDCACMLanguageCount]descStringLanguage{
|
||||
|
||||
{ // [0x0409] US English
|
||||
language: descLanguageEnglish,
|
||||
descriptor: descStringIndex{
|
||||
{ /* [0] Language */
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
// Actual string descriptors (index > 0) are copied into here at runtime!
|
||||
// This allows for application- or even user-defined string descriptors.
|
||||
{ /* [1] Manufacturer */ },
|
||||
{ /* [2] Product */ },
|
||||
{ /* [3] Serial Number */ },
|
||||
},
|
||||
},
|
||||
},
|
||||
device: &[descLengthDevice]uint8{
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
},
|
||||
qualif: &[descLengthQualification]uint8{
|
||||
descLengthQualification, // Size of this descriptor in bytes
|
||||
descTypeQualification, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
0, // Class code (assigned by the USB-IF).
|
||||
0, // Subclass code (assigned by the USB-IF).
|
||||
0, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
0, // Reserved
|
||||
},
|
||||
config: &[descCDCACMConfigSize]uint8{
|
||||
descLengthConfigure, // Size of this descriptor in bytes
|
||||
descTypeConfigure, // Descriptor Type
|
||||
lsU8(descCDCACMConfigSize), // Total length of data returned for this configuration (low)
|
||||
msU8(descCDCACMConfigSize), // Total length of data returned for this configuration (high)
|
||||
descCDCACMInterfaceCount, // Number of interfaces supported by this configuration
|
||||
1, // Value to use to select this configuration (1 = CDC-ACM[0])
|
||||
0, // Index of string descriptor describing this configuration
|
||||
descEndptConfigAttr, // Configuration attributes
|
||||
descCDCACMMaxPowerMa >> 1, // Max power consumption when fully-operational (2 mA units)
|
||||
|
||||
// Communication/Control Interface Descriptor
|
||||
descLengthInterface, // Descriptor length
|
||||
descTypeInterface, // Descriptor type
|
||||
descCDCACMInterfaceCtrl, // Interface index
|
||||
0, // Alternate setting
|
||||
1, // Number of endpoints
|
||||
descCDCTypeComm, // Class code
|
||||
descCDCSubAbstractControl, // Subclass code
|
||||
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
|
||||
descCDCACMInterfaceData, // Data Interface
|
||||
|
||||
// CDC Abstract Control Management Functional Descriptor
|
||||
descCDCFuncLengthAbstractControl, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeAbstractControl, // Descriptor Subtype
|
||||
0x06, // Capabilities
|
||||
|
||||
// CDC Union Functional Descriptor
|
||||
descCDCFuncLengthUnion, // Size of this descriptor in bytes
|
||||
descTypeCDCInterface, // Descriptor Type
|
||||
descCDCFuncTypeUnion, // Descriptor Subtype
|
||||
descCDCACMInterfaceCtrl, // Controlling interface index
|
||||
descCDCACMInterfaceData, // Controlled interface index
|
||||
|
||||
// Communication/Control Notification Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointStatus | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeInterrupt, // Attributes
|
||||
lsU8(descCDCACMStatusPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMStatusPacketSize), // Max packet size (high)
|
||||
descCDCACMStatusInterval, // Polling Interval
|
||||
|
||||
// Data Interface Descriptor
|
||||
descLengthInterface, // Interface length
|
||||
descTypeInterface, // Interface type
|
||||
descCDCACMInterfaceData, // Interface index
|
||||
0, // Alternate setting
|
||||
2, // Number of endpoints
|
||||
descCDCTypeData, // Class code
|
||||
descCDCSubNone, // Subclass code
|
||||
descCDCProtoNone, // Protocol code
|
||||
0, // Interface Description String Index
|
||||
|
||||
// Data Bulk Rx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataRx | // Endpoint address
|
||||
descEndptAddrDirectionOut,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataRxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataRxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
|
||||
// Data Bulk Tx Endpoint descriptor
|
||||
descLengthEndpoint, // Size of this descriptor in bytes
|
||||
descTypeEndpoint, // Descriptor Type
|
||||
descCDCACMEndpointDataTx | // Endpoint address
|
||||
descEndptAddrDirectionIn,
|
||||
descEndptTypeBulk, // Attributes
|
||||
lsU8(descCDCACMDataTxPacketSize), // Max packet size (low)
|
||||
msU8(descCDCACMDataTxPacketSize), // Max packet size (high)
|
||||
0, // Polling Interval
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Common configuration constants for the USB HID device class.
|
||||
const (
|
||||
descHIDLanguageCount = 1 // String descriptor languages available
|
||||
|
||||
descHIDInterfaceCount = 5 // Interfaces for all HID configurations.
|
||||
descHIDEndpointCount = 6 // Endpoints for all HID configurations.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ const descCPUFrequencyHz = 120000000
|
||||
// host/device controller instances.
|
||||
const descCoreCount = 1 // SAMx51 has a single, full-speed USB PHY
|
||||
|
||||
// descCDCACMCount defines the number of USB cores that may be configured as
|
||||
// descCDCCount defines the number of USB cores that may be configured as
|
||||
// CDC-ACM (single) devices.
|
||||
const descCDCACMCount = 1
|
||||
const descCDCCount = 0
|
||||
|
||||
// descHIDCount defines the number of USB cores that may be configured as a
|
||||
// composite (keyboard + mouse + joystick) human interface device (HID).
|
||||
const descHIDCount = 0
|
||||
const descHIDCount = 1
|
||||
|
||||
// General USB device identification constants.
|
||||
const (
|
||||
@@ -40,443 +40,3 @@ const (
|
||||
|
||||
descControlPacketSize = 64
|
||||
)
|
||||
|
||||
// Constants for USB CDC-ACM device classes.
|
||||
const (
|
||||
|
||||
// USB Bus Configuration Attributes
|
||||
|
||||
descCDCACMMaxPowerMa = 100 // Maximum current (mA) requested from host
|
||||
|
||||
// CDC-ACM Endpoint Descriptor Buffers
|
||||
|
||||
descCDCACMEDCount = 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).
|
||||
descCDCACMSxSize = 8 + 2
|
||||
descCDCACMCxSize = descControlPacketSize
|
||||
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
descCDCACMRxSize = descCDCACMDataRxPacketSize
|
||||
descCDCACMTxSize = descCDCACMDataTxPacketSize
|
||||
|
||||
descCDCACMTxTimeoutMs = 120 // millisec
|
||||
descCDCACMTxSyncUs = 75 // microsec
|
||||
|
||||
// Default CDC-ACM Endpoint Configurations (Full-Speed)
|
||||
|
||||
descCDCACMStatusInterval = descCDCACMStatusFSInterval // Status
|
||||
descCDCACMStatusPacketSize = descCDCACMStatusFSPacketSize //
|
||||
|
||||
descCDCACMDataRxPacketSize = descCDCACMDataRxFSPacketSize // Data Rx
|
||||
descCDCACMDataTxPacketSize = descCDCACMDataTxFSPacketSize // Data Tx
|
||||
|
||||
// CDC-ACM Endpoint Configurations for Full-Speed Device
|
||||
|
||||
descCDCACMStatusFSInterval = 5 // Status
|
||||
descCDCACMStatusFSPacketSize = 64 // (full-speed)
|
||||
|
||||
descCDCACMDataRxFSPacketSize = 64 // Data Rx (full-speed)
|
||||
descCDCACMDataTxFSPacketSize = 64 // Data Tx (full-speed)
|
||||
|
||||
// CDC-ACM Endpoint Configurations for High-Speed Device
|
||||
|
||||
// - N/A, SAMx51 only has a full-speed PHY
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// descCDCACM0ED 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 descCDCACM0ED [descCDCACMEDCount]dhwEPAddrDesc
|
||||
|
||||
// descCDCACM0Sx 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 descCDCACM0Sx [descCDCACMSxSize]uint8
|
||||
|
||||
// descCDCACM0Cx 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 descCDCACM0Cx [descCDCACMCxSize]uint8
|
||||
|
||||
// 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
|
||||
|
||||
// descCDCACM0Rx is the receive (Rx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Rx [descCDCACMRxSize]uint8
|
||||
|
||||
// descCDCACM0Tx is the transmit (Tx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Tx [descCDCACMTxSize]uint8
|
||||
|
||||
// descCDCACM0Rq is the receive (Rx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Rq [descCDCACMRxSize]uint8
|
||||
|
||||
// descCDCACM0Tq is the transmit (Tx) transfer buffer for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Tq [descCDCACMTxSize]uint8
|
||||
|
||||
// descCDCACM0LC is the emulated UART's line coding configuration for the
|
||||
// default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0LC descCDCACMLineCoding
|
||||
|
||||
// descCDCACM0LS is the emulated UART's line state for the default CDC-ACM
|
||||
// (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0LS descCDCACMLineState
|
||||
|
||||
// descCDCACMClassData 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 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
|
||||
|
||||
ed *[descCDCACMEDCount]dhwEPAddrDesc // endpoint descriptors
|
||||
|
||||
sx *[descCDCACMSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
|
||||
cx *[descCDCACMCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
|
||||
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
||||
tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
||||
|
||||
rxq *[descCDCACMRxSize]uint8
|
||||
txq *[descCDCACMTxSize]uint8
|
||||
|
||||
lc *descCDCACMLineCoding // UART line coding
|
||||
ls *descCDCACMLineState // UART line state
|
||||
|
||||
rq *Queue
|
||||
tq *Queue
|
||||
|
||||
sxSize uint32
|
||||
rxSize uint32
|
||||
txSize uint32
|
||||
}
|
||||
|
||||
// descCDCACMData 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 descCDCACM.
|
||||
var descCDCACMData = [dcdCount]descCDCACMClassData{
|
||||
|
||||
{ // -- CDC-ACM (single) Class Configuration Index 1 --
|
||||
|
||||
// CDC-ACM Control Buffers
|
||||
|
||||
ed: &descCDCACM0ED,
|
||||
|
||||
sx: &descCDCACM0Sx,
|
||||
cx: &descCDCACM0Cx,
|
||||
dx: &descCDCACM0Dx,
|
||||
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
rx: &descCDCACM0Rx,
|
||||
tx: &descCDCACM0Tx,
|
||||
|
||||
rxq: &descCDCACM0Rq,
|
||||
txq: &descCDCACM0Tq,
|
||||
|
||||
lc: &descCDCACM0LC,
|
||||
ls: &descCDCACM0LS,
|
||||
|
||||
rq: &Queue{},
|
||||
tq: &Queue{},
|
||||
|
||||
sxSize: descCDCACMStatusPacketSize,
|
||||
rxSize: descCDCACMDataRxPacketSize,
|
||||
txSize: descCDCACMDataTxPacketSize,
|
||||
},
|
||||
}
|
||||
|
||||
// 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 transmit (Tx) transfer buffer for the
|
||||
// default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0KeyboardTx [descHIDKeyboardTxSize]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
|
||||
|
||||
// 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 *[descHIDKeyboardTxSize]uint8 // interrupt endpoint keyboard Tx (IN) transfer buffer
|
||||
tpKeyboard *[descHIDKeyboardTxPacketSize]uint8 // interrupt endpoint keyboard Tx (IN) HID report bbuffer
|
||||
|
||||
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,
|
||||
tpKeyboard: &descHID0KeyboardTp,
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
//go:build baremetal && usb.cdc && (atsamd51 || atsame5x)
|
||||
// +build baremetal
|
||||
// +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
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
//go:build baremetal && usb.hid && (atsamd51 || atsame5x)
|
||||
// +build baremetal
|
||||
// +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]
|
||||
|
||||
if !consumer {
|
||||
|
||||
hid.txKeyboard[0] = hid.keyboard.mod
|
||||
hid.txKeyboard[1] = 0
|
||||
hid.txKeyboard[2] = hid.keyboard.key[0]
|
||||
hid.txKeyboard[3] = hid.keyboard.key[1]
|
||||
hid.txKeyboard[4] = hid.keyboard.key[2]
|
||||
hid.txKeyboard[5] = hid.keyboard.key[3]
|
||||
hid.txKeyboard[6] = hid.keyboard.key[4]
|
||||
hid.txKeyboard[7] = hid.keyboard.key[5]
|
||||
|
||||
return d.keyboardWrite(txEndpoint(descHIDEndpointKeyboard), hid.txKeyboard[:])
|
||||
|
||||
} else {
|
||||
|
||||
// 44444444 44333333 33332222 22222211 11111111 [ word ]
|
||||
// 98765432 10987654 32109876 54321098 76543210 [ index ] (right-to-left)
|
||||
|
||||
hid.txKeyboard[1] = uint8((hid.keyboard.con[1] << 2) | ((hid.keyboard.con[0] >> 8) & 0x03))
|
||||
hid.txKeyboard[2] = uint8((hid.keyboard.con[2] << 4) | ((hid.keyboard.con[1] >> 6) & 0x0F))
|
||||
hid.txKeyboard[3] = uint8((hid.keyboard.con[3] << 6) | ((hid.keyboard.con[2] >> 4) & 0x3F))
|
||||
hid.txKeyboard[4] = uint8(hid.keyboard.con[3] >> 2)
|
||||
hid.txKeyboard[5] = hid.keyboard.sys[0]
|
||||
hid.txKeyboard[6] = hid.keyboard.sys[1]
|
||||
hid.txKeyboard[7] = hid.keyboard.sys[2]
|
||||
|
||||
return d.keyboardWrite(txEndpoint(descHIDEndpointMediaKey), hid.txKeyboard[:])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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(&hid.txKeyboard[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)
|
||||
}
|
||||
@@ -170,14 +170,7 @@ func (d *dhw) init() status {
|
||||
(3 << sam.USB_DEVICE_QOSCTRL_DQOS_Pos))
|
||||
|
||||
// Install USB endpoint descriptor table (USB_DEVICE.DESCADD)
|
||||
var addr uintptr
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
addr = uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].ed[0]))
|
||||
case classDeviceHID:
|
||||
addr = uintptr(unsafe.Pointer(&descHID[d.cc.config-1].ed[0]))
|
||||
}
|
||||
d.bus.DESCADD.Set(uint32(addr))
|
||||
d.bus.DESCADD.Set(uint32(d.descriptorTable()))
|
||||
|
||||
// Configure bus speed (always full-speed (FS)), device mode, enable PHY, and
|
||||
// put finite-state machine (FSM) in standby.
|
||||
@@ -438,51 +431,6 @@ func (d *dhw) remoteWakeup() {
|
||||
// Control Endpoint 0
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) controlEndpoint() uint8 {
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return descCDCACMEndpointCtrl
|
||||
case classDeviceHID:
|
||||
return descHIDEndpointCtrl
|
||||
}
|
||||
return descEndpointInvalid
|
||||
}
|
||||
|
||||
func (d *dhw) controlSetupBuffer() uintptr {
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].sx[0]))
|
||||
case classDeviceHID:
|
||||
return uintptr(unsafe.Pointer(&descHID[d.cc.config-1].sx[0]))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (d *dhw) controlStatusBuffer(data []uint8) uintptr {
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
// reference to class configuration data
|
||||
c := descCDCACM[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]))
|
||||
|
||||
case classDeviceHID:
|
||||
// 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]))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
|
||||
// any other endpoint, use method endpointStall().
|
||||
func (d *dhw) controlStall(stall bool, dir uint8) {
|
||||
@@ -1046,71 +994,6 @@ func (d *dhw) endpointDescriptors(endpoint uint8) (out, in *dhwEPDesc) {
|
||||
d.endpointDescriptor(txEndpoint(endpoint))
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// endpoint descriptor is device class-specific
|
||||
num, dir := unpackEndpoint(endpoint)
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return &descCDCACM[d.cc.config-1].ed[num][dir]
|
||||
case classDeviceHID:
|
||||
return &descHID[d.cc.config-1].ed[num][dir]
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) endpointMaxPacketSize(endpoint uint8) uint32 {
|
||||
|
||||
switch d.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
|
||||
switch endpointNumber(endpoint) {
|
||||
case descCDCACMEndpointCtrl:
|
||||
return descControlPacketSize
|
||||
|
||||
case descCDCACMEndpointStatus:
|
||||
return descCDCACMStatusPacketSize
|
||||
|
||||
case descCDCACMEndpointDataRx:
|
||||
return descCDCACMDataRxPacketSize
|
||||
|
||||
case descCDCACMEndpointDataTx:
|
||||
return descCDCACMDataTxPacketSize
|
||||
}
|
||||
case classDeviceHID:
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
|
||||
|
||||
if control {
|
||||
@@ -1309,425 +1192,3 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
|
||||
func (d *dhw) endpointComplete(endpoint uint8, size uint32) {
|
||||
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// General-Purpose (GP) Timer
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) timerConfigure(timer int, usec uint32, fn func()) {
|
||||
|
||||
}
|
||||
|
||||
func (d *dhw) timerOneShot(timer int) {
|
||||
|
||||
}
|
||||
|
||||
func (d *dhw) timerStop(timer int) {
|
||||
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [CDC-ACM] Serial UART (Virtual COM Port)
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) uartConfigure() {
|
||||
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
|
||||
acm.setState(descCDCACMStateConfigured)
|
||||
|
||||
// SAMx51 only supports USB full-speed (FS) operation
|
||||
acm.sxSize = descCDCACMStatusFSPacketSize
|
||||
acm.rxSize = descCDCACMDataRxFSPacketSize
|
||||
acm.txSize = descCDCACMDataTxFSPacketSize
|
||||
|
||||
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(descCDCACMEndpointStatus),
|
||||
false, descCDCACMConfigAttrStatus)
|
||||
d.endpointEnable(rxEndpoint(descCDCACMEndpointDataRx),
|
||||
false, descCDCACMConfigAttrDataRx)
|
||||
d.endpointEnable(txEndpoint(descCDCACMEndpointDataTx),
|
||||
false, descCDCACMConfigAttrDataTx)
|
||||
|
||||
d.endpointConfigure(txEndpoint(descCDCACMEndpointStatus),
|
||||
nil)
|
||||
d.endpointConfigure(rxEndpoint(descCDCACMEndpointDataRx),
|
||||
d.uartReceiveComplete)
|
||||
d.endpointConfigure(txEndpoint(descCDCACMEndpointDataTx),
|
||||
d.uartTransmitComplete)
|
||||
|
||||
d.uartReceiveStart(rxEndpoint(descCDCACMEndpointDataRx))
|
||||
}
|
||||
|
||||
func (d *dhw) uartSetLineState(state uint16) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
acm.setState(descCDCACMStateLineState)
|
||||
if acm.ls.parse(state) {
|
||||
// TBD: respond to changes in line state?
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) uartSetLineCoding(coding []uint8) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
acm.setState(descCDCACMStateLineCoding)
|
||||
if acm.lc.parse(coding) {
|
||||
switch acm.lc.baud {
|
||||
case 1200:
|
||||
if acm.ls.dataTerminalReady {
|
||||
// reboot CPU
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) uartReady() bool {
|
||||
acm := &descCDCACM[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).
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// The "set" method on type descCDCACMState defines this incremental state
|
||||
// machine, with the UART's current state stored in the volatile.Register8
|
||||
// field "state" of descCDCACMClass.
|
||||
return d.state() == dcdStateConfigured && //acm.ls.dataTerminalReady &&
|
||||
acm.state.Get() == uint8(descCDCACMStateLineCoding)
|
||||
}
|
||||
|
||||
func (d *dhw) uartReceiveStart(endpoint uint8) {
|
||||
acm := &descCDCACM[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) uartReceiveComplete(endpoint uint8, size uint32) {
|
||||
acm := &descCDCACM[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.uartReceiveStart(endpoint)
|
||||
}
|
||||
|
||||
func (d *dhw) uartTransmitStart(endpoint uint8) {
|
||||
acm := &descCDCACM[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) uartTransmitComplete(endpoint uint8, size uint32) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||
if size > 0 && size%acm.txSize == 0 {
|
||||
// Send ZLP if transfer length is a multiple of max packet size.
|
||||
d.endpointTransfer(endpoint, 0, 0)
|
||||
}
|
||||
d.ep[num][descDirTx].setActiveTransfer(nil)
|
||||
d.uartTransmitStart(endpoint)
|
||||
}
|
||||
|
||||
// uartFlush discards all buffered input (Rx) data.
|
||||
func (d *dhw) uartFlush() {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
acm.rq.Reset(int(acm.rxSize))
|
||||
}
|
||||
|
||||
func (d *dhw) uartAvailable() int {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
return acm.rq.Len()
|
||||
}
|
||||
|
||||
func (d *dhw) uartPeek() (uint8, bool) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
return acm.rq.Front()
|
||||
}
|
||||
|
||||
func (d *dhw) uartReadByte() (uint8, bool) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
return acm.rq.Deq()
|
||||
}
|
||||
|
||||
func (d *dhw) uartRead(data []uint8) (int, error) {
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
return acm.rq.Read(data)
|
||||
}
|
||||
|
||||
func (d *dhw) uartWriteByte(c uint8) error {
|
||||
_, err := d.uartWrite([]uint8{c})
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *dhw) uartWrite(data []uint8) (int, error) {
|
||||
|
||||
acm := &descCDCACM[d.cc.config-1]
|
||||
num := uint16(descCDCACMEndpointDataTx) & 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.uartTransmitStart(txEndpoint(descCDCACMEndpointDataTx))
|
||||
}
|
||||
}
|
||||
|
||||
return sent, werr
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [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 = descHIDKeyboardTxFSPacketSize
|
||||
|
||||
d.endpointEnable(descHIDEndpointKeyboard,
|
||||
false, descHIDConfigAttrKeyboard)
|
||||
d.endpointEnable(descHIDEndpointMediaKey,
|
||||
false, descHIDConfigAttrMediaKey)
|
||||
|
||||
// d.endpointConfigureTx(descHIDEndpointKeyboard,
|
||||
// hid.txKeyboardSize, false, nil)
|
||||
// d.endpointConfigureTx(descHIDEndpointMediaKey,
|
||||
// hid.txKeyboardSize, false, nil)
|
||||
}
|
||||
|
||||
func (d *dhw) keyboardSendKeys(consumer bool) bool {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
if !consumer {
|
||||
|
||||
hid.tpKeyboard[0] = hid.keyboard.mod
|
||||
hid.tpKeyboard[1] = 0
|
||||
hid.tpKeyboard[2] = hid.keyboard.key[0]
|
||||
hid.tpKeyboard[3] = hid.keyboard.key[1]
|
||||
hid.tpKeyboard[4] = hid.keyboard.key[2]
|
||||
hid.tpKeyboard[5] = hid.keyboard.key[3]
|
||||
hid.tpKeyboard[6] = hid.keyboard.key[4]
|
||||
hid.tpKeyboard[7] = hid.keyboard.key[5]
|
||||
|
||||
return d.keyboardWrite(descHIDEndpointKeyboard, hid.tpKeyboard[:])
|
||||
|
||||
} else {
|
||||
|
||||
// 44444444 44333333 33332222 22222211 11111111 [ word ]
|
||||
// 98765432 10987654 32109876 54321098 76543210 [ index ] (right-to-left)
|
||||
|
||||
hid.tpKeyboard[1] = uint8((hid.keyboard.con[1] << 2) | ((hid.keyboard.con[0] >> 8) & 0x03))
|
||||
hid.tpKeyboard[2] = uint8((hid.keyboard.con[2] << 4) | ((hid.keyboard.con[1] >> 6) & 0x0F))
|
||||
hid.tpKeyboard[3] = uint8((hid.keyboard.con[3] << 6) | ((hid.keyboard.con[2] >> 4) & 0x3F))
|
||||
hid.tpKeyboard[4] = uint8(hid.keyboard.con[3] >> 2)
|
||||
hid.tpKeyboard[5] = hid.keyboard.sys[0]
|
||||
hid.tpKeyboard[6] = hid.keyboard.sys[1]
|
||||
hid.tpKeyboard[7] = hid.keyboard.sys[2]
|
||||
|
||||
return d.keyboardWrite(descHIDEndpointMediaKey, hid.tpKeyboard[:])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dhw) keyboardWrite(endpoint uint8, data []uint8) bool {
|
||||
|
||||
// hid := &descHID[d.cc.config-1]
|
||||
|
||||
// size := uint16(len(data))
|
||||
// xfer := &hid.tdKeyboard[hid.txKeyboardHead]
|
||||
// when := ticks()
|
||||
// for {
|
||||
// if 0 == xfer.token&0x80 {
|
||||
// if 0 != xfer.token&0x68 {
|
||||
// // TODO: token contains error, how to handle?
|
||||
// }
|
||||
// hid.txKeyboardPrev = false
|
||||
// break
|
||||
// }
|
||||
// if hid.txKeyboardPrev {
|
||||
// return false
|
||||
// }
|
||||
// if ticks()-when > descHIDKeyboardTxTimeoutMs {
|
||||
// // Waited too long, assume host connection dropped
|
||||
// hid.txKeyboardPrev = true
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// // Without this delay, the order packets are transmitted is seriously screwy.
|
||||
// udelay(60)
|
||||
// buff := hid.txKeyboard[hid.txKeyboardHead*descHIDKeyboardTxSize:]
|
||||
// _ = copy(buff, data)
|
||||
// d.transferPrepare(xfer, &buff[0], size, 0)
|
||||
// flushCache(uintptr(unsafe.Pointer(&buff[0])), descHIDKeyboardTxSize)
|
||||
// d.endpointTransmit(endpoint, xfer)
|
||||
// hid.txKeyboardHead += 1
|
||||
// if hid.txKeyboardHead >= descHIDKeyboardTDCount {
|
||||
// hid.txKeyboardHead = 0
|
||||
// }
|
||||
return true
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// [HID] Mouse
|
||||
// =============================================================================
|
||||
|
||||
func (d *dhw) mouseConfigure() {
|
||||
|
||||
hid := &descHID[d.cc.config-1]
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package usb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUARTInvalidPort = errors.New("invalid USB port")
|
||||
ErrUARTEmptyBuffer = errors.New("USB receive buffer empty")
|
||||
)
|
||||
|
||||
// UART represents a virtual serial (UART) device emulation using the USB
|
||||
// CDC-ACM device class driver.
|
||||
type UART struct {
|
||||
// Port is the MCU's native USB core number. If in doubt, leave it
|
||||
// uninitialized for default (0).
|
||||
Port int
|
||||
core *core
|
||||
}
|
||||
|
||||
type UARTConfig struct {
|
||||
BusSpeed Speed
|
||||
}
|
||||
|
||||
func (uart *UART) Configure(config UARTConfig) error {
|
||||
|
||||
c := class{id: classDeviceCDCACM, config: 1}
|
||||
|
||||
// verify we have a free USB port and take ownership of it
|
||||
var st status
|
||||
uart.core, st = initCore(uart.Port, config.BusSpeed, c)
|
||||
if !st.ok() {
|
||||
return ErrUARTInvalidPort
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) Ready() bool {
|
||||
return uart.core.dc.uartReady()
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (uart *UART) Buffered() int {
|
||||
for !uart.Ready() {
|
||||
}
|
||||
return uart.core.dc.uartAvailable()
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (uart *UART) ReadByte() (byte, error) {
|
||||
for !uart.Ready() {
|
||||
}
|
||||
n, ok := uart.core.dc.uartReadByte()
|
||||
if !ok {
|
||||
return 0, ErrUARTEmptyBuffer
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (uart *UART) Read(data []byte) (n int, err error) {
|
||||
for !uart.Ready() {
|
||||
}
|
||||
return uart.core.dc.uartRead(data)
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte of data to the UART interface.
|
||||
func (uart *UART) WriteByte(c byte) error {
|
||||
for !uart.Ready() {
|
||||
}
|
||||
return uart.core.dc.uartWriteByte(c)
|
||||
}
|
||||
|
||||
// Write data to the UART.
|
||||
func (uart *UART) Write(data []byte) (n int, err error) {
|
||||
for !uart.Ready() {
|
||||
}
|
||||
return uart.core.dc.uartWrite(data)
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//go:build baremetal && usb.cdc
|
||||
// +build baremetal,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)
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,usb.hid
|
||||
|
||||
package usb
|
||||
|
||||
import "errors"
|
||||
@@ -57,6 +60,10 @@ func (kb *Keyboard) configure(dc *dcd, hc *descHIDClass) {
|
||||
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.
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,usb.hid
|
||||
|
||||
package usb
|
||||
|
||||
import (
|
||||
@@ -36,6 +39,10 @@ func (hid *HID) Configure(config HIDConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hid *HID) Ready() bool {
|
||||
return hid.core.dc.keyboard().ready()
|
||||
}
|
||||
|
||||
func (hid *HID) Keyboard() *Keyboard {
|
||||
return hid.core.dc.keyboard()
|
||||
}
|
||||
@@ -120,15 +120,15 @@ type class struct {
|
||||
|
||||
// Enumerated constants for all supported host/device class configurations.
|
||||
const (
|
||||
classDeviceCDCACM = 0
|
||||
classDeviceHID = 1
|
||||
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 classDeviceCDCACM, classDeviceHID:
|
||||
case classDeviceCDC, classDeviceHID:
|
||||
return modeDevice
|
||||
default:
|
||||
return modeIdle
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"machine"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
)
|
||||
@@ -28,11 +27,13 @@ func init() {
|
||||
initSERCOMClocks()
|
||||
initADCClock()
|
||||
|
||||
// connect to USB CDC interface
|
||||
machine.Serial.Configure(usb.UARTConfig{})
|
||||
if !machine.USB.Configured() {
|
||||
machine.USB.Configure(usb.UARTConfig{})
|
||||
}
|
||||
//// connect to USB CDC interface
|
||||
//machine.Serial.Configure(usb.UARTConfig{})
|
||||
//if !machine.USB.Configured() {
|
||||
// machine.USB.Configure(usb.UARTConfig{})
|
||||
//}
|
||||
|
||||
initUSB()
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build baremetal && usb.cdc
|
||||
// +build baremetal,usb.cdc
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
func initUSB() {
|
||||
// Configure CDC interface.
|
||||
machine.USB.Configure(usb.CDCConfig{})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build baremetal && usb.hid
|
||||
// +build baremetal,usb.hid
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
func initUSB() {
|
||||
// Configure HID interface.
|
||||
machine.USB.Configure(usb.HIDConfig{})
|
||||
}
|
||||
Reference in New Issue
Block a user