refactor USB package with device class build tags

added basic HID keyboard support for SAMx51 (not fully-functional)
This commit is contained in:
sago35
2022-05-12 20:35:17 +09:00
parent 3b892cbe41
commit 4b81985d2b
25 changed files with 2768 additions and 2684 deletions
+4 -1
View File
@@ -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 {
-6
View File
@@ -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
-8
View File
@@ -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})
}
+14
View File
@@ -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})
}
+14
View File
@@ -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})
}
+277
View File
@@ -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
}
}
+375
View File
@@ -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
View File
@@ -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)
}
}
+399
View File
@@ -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
},
},
}
+241
View File
@@ -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,
},
}
+511
View File
@@ -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
}
+271
View File
@@ -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
View File
@@ -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
}
+3 -443
View File
@@ -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,
},
}
+244
View File
@@ -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
}
+265
View File
@@ -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)
}
+1 -540
View File
@@ -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)
}
-80
View File
@@ -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)
}
+83
View File
@@ -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()
}
+3 -3
View File
@@ -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 -6
View File
@@ -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) {
+14
View File
@@ -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{})
}
+14
View File
@@ -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{})
}