machine/usb: refactorings to move functionality under machine/usb package

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram
2022-07-12 22:31:23 +02:00
committed by Ron Evans
parent ea36fea5a9
commit 3c2d2a93d3
9 changed files with 279 additions and 271 deletions
+64 -195
View File
@@ -5,7 +5,7 @@ package machine
import (
"errors"
"runtime/volatile"
"machine/usb"
)
type USBDevice struct {
@@ -27,15 +27,9 @@ type Serialer interface {
RTS() bool
}
var usbDescriptor = descriptorCDC
var usbDescriptor = usb.DescriptorCDC
const (
usbDescriptorConfigCDC = 1 << iota
usbDescriptorConfigHID
usbDescriptorConfigMIDI
)
var usbDescriptorConfig uint8 = usbDescriptorConfigCDC
var usbDescriptorConfig uint8 = usb.DescriptorConfigCDC
// strToUTF16LEDescriptor converts a utf8 string into a string descriptor
// note: the following code only converts ascii characters to UTF16LE. In order
@@ -44,7 +38,7 @@ var usbDescriptorConfig uint8 = usbDescriptorConfigCDC
// binary.
func strToUTF16LEDescriptor(in string, out []byte) {
out[0] = byte(len(out))
out[1] = usb_STRING_DESCRIPTOR_TYPE
out[1] = usb.STRING_DESCRIPTOR_TYPE
for i, rune := range in {
out[(i<<1)+2] = byte(rune)
out[(i<<1)+3] = 0
@@ -52,11 +46,6 @@ func strToUTF16LEDescriptor(in string, out []byte) {
return
}
var (
// TODO: allow setting these
usb_STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English
)
const cdcLineInfoSize = 7
var (
@@ -65,7 +54,7 @@ var (
)
var (
usbEndpointDescriptors [numberOfEndpoints]usbDeviceDescriptor
usbEndpointDescriptors [usb.NumberOfEndpoints]usb.DeviceDescriptor
udd_ep_control_cache_buffer [256]uint8
udd_ep_in_cache_buffer [7][64]uint8
@@ -78,191 +67,71 @@ var (
usbSetInterface uint8
)
const (
usb_IMANUFACTURER = 1
usb_IPRODUCT = 2
usb_ISERIAL = 3
usb_ENDPOINT_TYPE_DISABLE = 0xFF
usb_ENDPOINT_TYPE_CONTROL = 0x00
usb_ENDPOINT_TYPE_ISOCHRONOUS = 0x01
usb_ENDPOINT_TYPE_BULK = 0x02
usb_ENDPOINT_TYPE_INTERRUPT = 0x03
usb_DEVICE_DESCRIPTOR_TYPE = 1
usb_CONFIGURATION_DESCRIPTOR_TYPE = 2
usb_STRING_DESCRIPTOR_TYPE = 3
usb_INTERFACE_DESCRIPTOR_TYPE = 4
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
usb_DEVICE_QUALIFIER = 6
usb_OTHER_SPEED_CONFIGURATION = 7
usb_SET_REPORT_TYPE = 33
usb_HID_REPORT_TYPE = 34
usbEndpointOut = 0x00
usbEndpointIn = 0x80
numberOfEndpoints = 8
usbEndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024
// standard requests
usb_GET_STATUS = 0
usb_CLEAR_FEATURE = 1
usb_SET_FEATURE = 3
usb_SET_ADDRESS = 5
usb_GET_DESCRIPTOR = 6
usb_SET_DESCRIPTOR = 7
usb_GET_CONFIGURATION = 8
usb_SET_CONFIGURATION = 9
usb_GET_INTERFACE = 10
usb_SET_INTERFACE = 11
// non standard requests
usb_SET_IDLE = 10
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
usb_DEVICE_CLASS_STORAGE = 0x08
usb_DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF
usb_CONFIG_POWERED_MASK = 0x40
usb_CONFIG_BUS_POWERED = 0x80
usb_CONFIG_SELF_POWERED = 0xC0
usb_CONFIG_REMOTE_WAKEUP = 0x20
// Interface
numberOfInterfaces = 3
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
usb_CDC_DATA_INTERFACE = 1 // CDC Data
usb_CDC_FIRST_ENDPOINT = 1
usb_HID_INTERFACE = 2 // HID
// Endpoint
usb_CONTROL_ENDPOINT = 0
usb_CDC_ENDPOINT_ACM = 1
usb_CDC_ENDPOINT_OUT = 2
usb_CDC_ENDPOINT_IN = 3
usb_HID_ENDPOINT_IN = 4
usb_MIDI_ENDPOINT_OUT = 5
usb_MIDI_ENDPOINT_IN = 6
// bmRequestType
usb_REQUEST_HOSTTODEVICE = 0x00
usb_REQUEST_DEVICETOHOST = 0x80
usb_REQUEST_DIRECTION = 0x80
usb_REQUEST_STANDARD = 0x00
usb_REQUEST_CLASS = 0x20
usb_REQUEST_VENDOR = 0x40
usb_REQUEST_TYPE = 0x60
usb_REQUEST_DEVICE = 0x00
usb_REQUEST_INTERFACE = 0x01
usb_REQUEST_ENDPOINT = 0x02
usb_REQUEST_OTHER = 0x03
usb_REQUEST_RECIPIENT = 0x1F
usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE)
)
var (
usbTxHandler [numberOfEndpoints]func()
usbRxHandler [numberOfEndpoints]func([]byte)
usbSetupHandler [numberOfInterfaces]func(USBSetup) bool
usbTxHandler [usb.NumberOfEndpoints]func()
usbRxHandler [usb.NumberOfEndpoints]func([]byte)
usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool
endPoints = []uint32{
usb_CONTROL_ENDPOINT: usb_ENDPOINT_TYPE_CONTROL,
usb_CDC_ENDPOINT_ACM: (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
usb_CDC_ENDPOINT_OUT: (usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
usb_CDC_ENDPOINT_IN: (usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
usb_HID_ENDPOINT_IN: (usb_ENDPOINT_TYPE_DISABLE), // Interrupt In
usb_MIDI_ENDPOINT_OUT: (usb_ENDPOINT_TYPE_DISABLE), // Bulk Out
usb_MIDI_ENDPOINT_IN: (usb_ENDPOINT_TYPE_DISABLE), // Bulk In
usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL,
usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn),
usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut),
usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn),
usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In
usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out
usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In
}
)
// usbDeviceDescBank is the USB device endpoint descriptor.
type usbDeviceDescBank struct {
ADDR volatile.Register32
PCKSIZE volatile.Register32
EXTREG volatile.Register16
STATUS_BK volatile.Register8
_reserved [5]volatile.Register8
}
type usbDeviceDescriptor struct {
DeviceDescBank [2]usbDeviceDescBank
}
type USBSetup struct {
BmRequestType uint8
BRequest uint8
WValueL uint8
WValueH uint8
WIndex uint16
WLength uint16
}
func newUSBSetup(data []byte) USBSetup {
u := USBSetup{}
u.BmRequestType = uint8(data[0])
u.BRequest = uint8(data[1])
u.WValueL = uint8(data[2])
u.WValueH = uint8(data[3])
u.WIndex = uint16(data[4]) | (uint16(data[5]) << 8)
u.WLength = uint16(data[6]) | (uint16(data[7]) << 8)
return u
}
// sendDescriptor creates and sends the various USB descriptor types that
// can be requested by the host.
func sendDescriptor(setup USBSetup) {
func sendDescriptor(setup usb.Setup) {
switch setup.WValueH {
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
case usb.CONFIGURATION_DESCRIPTOR_TYPE:
sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength)
return
case usb_DEVICE_DESCRIPTOR_TYPE:
case usb.DEVICE_DESCRIPTOR_TYPE:
// composite descriptor
if (usbDescriptorConfig & usbDescriptorConfigHID) > 0 {
usbDescriptor = descriptorCDCHID
} else if (usbDescriptorConfig & usbDescriptorConfigMIDI) > 0 {
usbDescriptor = descriptorCDCMIDI
} else {
usbDescriptor = descriptorCDC
switch {
case (usbDescriptorConfig & usb.DescriptorConfigHID) > 0:
usbDescriptor = usb.DescriptorCDCHID
case (usbDescriptorConfig & usb.DescriptorConfigMIDI) > 0:
usbDescriptor = usb.DescriptorCDCMIDI
default:
usbDescriptor = usb.DescriptorCDC
}
usbDescriptor.Configure(usb_VID, usb_PID)
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
return
case usb_STRING_DESCRIPTOR_TYPE:
case usb.STRING_DESCRIPTOR_TYPE:
switch setup.WValueL {
case 0:
b := []byte{0x04, 0x03, 0x09, 0x04}
sendUSBPacket(0, b, setup.WLength)
case usb_IPRODUCT:
case usb.IPRODUCT:
b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2)
strToUTF16LEDescriptor(usb_STRING_PRODUCT, b)
sendUSBPacket(0, b, setup.WLength)
case usb_IMANUFACTURER:
case usb.IMANUFACTURER:
b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2)
strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b)
sendUSBPacket(0, b, setup.WLength)
case usb_ISERIAL:
case usb.ISERIAL:
// TODO: allow returning a product serial number
SendZlp()
}
return
case usb_HID_REPORT_TYPE:
case usb.HID_REPORT_TYPE:
if h, ok := usbDescriptor.HID[setup.WIndex]; ok {
sendUSBPacket(0, h, setup.WLength)
return
}
case usb_DEVICE_QUALIFIER:
case usb.DEVICE_QUALIFIER:
// skip
default:
}
@@ -272,9 +141,9 @@ func sendDescriptor(setup USBSetup) {
return
}
func handleStandardSetup(setup USBSetup) bool {
func handleStandardSetup(setup usb.Setup) bool {
switch setup.BRequest {
case usb_GET_STATUS:
case usb.GET_STATUS:
buf := []byte{0, 0}
if setup.BmRequestType != 0 { // endpoint
@@ -286,7 +155,7 @@ func handleStandardSetup(setup USBSetup) bool {
sendUSBPacket(0, buf, setup.WLength)
return true
case usb_CLEAR_FEATURE:
case usb.CLEAR_FEATURE:
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = false
} else if setup.WValueL == 0 { // ENDPOINTHALT
@@ -295,7 +164,7 @@ func handleStandardSetup(setup USBSetup) bool {
SendZlp()
return true
case usb_SET_FEATURE:
case usb.SET_FEATURE:
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = true
} else if setup.WValueL == 0 { // ENDPOINTHALT
@@ -304,23 +173,23 @@ func handleStandardSetup(setup USBSetup) bool {
SendZlp()
return true
case usb_SET_ADDRESS:
case usb.SET_ADDRESS:
return handleUSBSetAddress(setup)
case usb_GET_DESCRIPTOR:
case usb.GET_DESCRIPTOR:
sendDescriptor(setup)
return true
case usb_SET_DESCRIPTOR:
case usb.SET_DESCRIPTOR:
return false
case usb_GET_CONFIGURATION:
case usb.GET_CONFIGURATION:
buff := []byte{usbConfiguration}
sendUSBPacket(0, buff, setup.WLength)
return true
case usb_SET_CONFIGURATION:
if setup.BmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
case usb.SET_CONFIGURATION:
if setup.BmRequestType&usb.REQUEST_RECIPIENT == usb.REQUEST_DEVICE {
for i := 1; i < len(endPoints); i++ {
initEndpoint(uint32(i), endPoints[i])
}
@@ -333,12 +202,12 @@ func handleStandardSetup(setup USBSetup) bool {
return false
}
case usb_GET_INTERFACE:
case usb.GET_INTERFACE:
buff := []byte{usbSetInterface}
sendUSBPacket(0, buff, setup.WLength)
return true
case usb_SET_INTERFACE:
case usb.SET_INTERFACE:
usbSetInterface = setup.WValueL
SendZlp()
@@ -349,30 +218,30 @@ func handleStandardSetup(setup USBSetup) bool {
}
}
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) {
usbDescriptorConfig |= usbDescriptorConfigCDC
endPoints[usb_CDC_ENDPOINT_ACM] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)
endPoints[usb_CDC_ENDPOINT_OUT] = (usb_ENDPOINT_TYPE_BULK | usbEndpointOut)
endPoints[usb_CDC_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_BULK | usbEndpointIn)
usbRxHandler[usb_CDC_ENDPOINT_OUT] = rxHandler
usbTxHandler[usb_CDC_ENDPOINT_IN] = txHandler
usbSetupHandler[usb_CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control)
usbSetupHandler[usb_CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data)
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
usbDescriptorConfig |= usb.DescriptorConfigCDC
endPoints[usb.CDC_ENDPOINT_ACM] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
endPoints[usb.CDC_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
endPoints[usb.CDC_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
usbRxHandler[usb.CDC_ENDPOINT_OUT] = rxHandler
usbTxHandler[usb.CDC_ENDPOINT_IN] = txHandler
usbSetupHandler[usb.CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control)
usbSetupHandler[usb.CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data)
}
// EnableHID enables HID. This function must be executed from the init().
func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) {
usbDescriptorConfig |= usbDescriptorConfigHID
endPoints[usb_HID_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)
usbTxHandler[usb_HID_ENDPOINT_IN] = txHandler
usbSetupHandler[usb_HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
usbDescriptorConfig |= usb.DescriptorConfigHID
endPoints[usb.HID_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
usbTxHandler[usb.HID_ENDPOINT_IN] = txHandler
usbSetupHandler[usb.HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
}
// EnableMIDI enables MIDI. This function must be executed from the init().
func EnableMIDI(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) {
usbDescriptorConfig |= usbDescriptorConfigMIDI
endPoints[usb_MIDI_ENDPOINT_OUT] = (usb_ENDPOINT_TYPE_BULK | usbEndpointOut)
endPoints[usb_MIDI_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_BULK | usbEndpointIn)
usbRxHandler[usb_MIDI_ENDPOINT_OUT] = rxHandler
usbTxHandler[usb_MIDI_ENDPOINT_IN] = txHandler
func EnableMIDI(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
usbDescriptorConfig |= usb.DescriptorConfigMIDI
endPoints[usb.MIDI_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
endPoints[usb.MIDI_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
usbRxHandler[usb.MIDI_ENDPOINT_OUT] = rxHandler
usbTxHandler[usb.MIDI_ENDPOINT_IN] = txHandler
}