aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine/usb
diff options
context:
space:
mode:
authordeadprogram <[email protected]>2023-04-02 12:12:32 +0200
committerRon Evans <[email protected]>2023-04-28 15:15:54 +0200
commit2ab7ee6a8a793f26278e67646fad5fa010bc3561 (patch)
tree3dc109f410b8ec73a7e87611a4e5bb095797ceb2 /src/machine/usb
parent6a2dd35fe63d6a99bcdb6156e8dd87fafc9f31b2 (diff)
downloadtinygo-2ab7ee6a8a793f26278e67646fad5fa010bc3561.tar.gz
tinygo-2ab7ee6a8a793f26278e67646fad5fa010bc3561.zip
machine/usb: refactoring descriptors into subpackage for modularity
Signed-off-by: deadprogram <[email protected]>
Diffstat (limited to 'src/machine/usb')
-rw-r--r--src/machine/usb/descriptor.go179
-rw-r--r--src/machine/usb/descriptor/cdc.go168
-rw-r--r--src/machine/usb/descriptor/classspecific.go17
-rw-r--r--src/machine/usb/descriptor/configuration.go49
-rw-r--r--src/machine/usb/descriptor/descriptor.go63
-rw-r--r--src/machine/usb/descriptor/device.go73
-rw-r--r--src/machine/usb/descriptor/endpoint.go111
-rw-r--r--src/machine/usb/descriptor/hid.go189
-rw-r--r--src/machine/usb/descriptor/interface.go49
-rw-r--r--src/machine/usb/descriptor/interfaceassociation.go45
-rw-r--r--src/machine/usb/descriptor/joystick.go145
-rw-r--r--src/machine/usb/descriptor/midi.go249
-rw-r--r--src/machine/usb/hid/joystick/state.go57
-rw-r--r--src/machine/usb/usb.go23
14 files changed, 1171 insertions, 246 deletions
diff --git a/src/machine/usb/descriptor.go b/src/machine/usb/descriptor.go
deleted file mode 100644
index d57d0bd8a..000000000
--- a/src/machine/usb/descriptor.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package usb
-
-import "runtime/volatile"
-
-// DeviceDescBank is the USB device endpoint descriptor.
-type DeviceDescBank struct {
- ADDR volatile.Register32
- PCKSIZE volatile.Register32
- EXTREG volatile.Register16
- STATUS_BK volatile.Register8
- _reserved [5]volatile.Register8
-}
-
-type DeviceDescriptor struct {
- DeviceDescBank [2]DeviceDescBank
-}
-
-type Descriptor struct {
- Device []byte
- Configuration []byte
- HID map[uint16][]byte
-}
-
-func (d *Descriptor) Configure(idVendor, idProduct uint16) {
- d.Device[8] = byte(idVendor)
- d.Device[9] = byte(idVendor >> 8)
- d.Device[10] = byte(idProduct)
- d.Device[11] = byte(idProduct >> 8)
-
- d.Configuration[2] = byte(len(d.Configuration))
- d.Configuration[3] = byte(len(d.Configuration) >> 8)
-}
-
-var DescriptorCDC = Descriptor{
- Device: []byte{
- 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
- },
- Configuration: []byte{
- 0x09, 0x02, 0x4b, 0x00, 0x02, 0x01, 0x00, 0xa0, 0x32,
- 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
- 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
- 0x05, 0x24, 0x00, 0x10, 0x01,
- 0x04, 0x24, 0x02, 0x06,
- 0x05, 0x24, 0x06, 0x00, 0x01,
- 0x05, 0x24, 0x01, 0x01, 0x01,
- 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
- 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
- 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
- 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
- },
-}
-
-var DescriptorCDCHID = Descriptor{
- Device: []byte{
- 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
- },
- Configuration: []byte{
- 0x09, 0x02, 0x64, 0x00, 0x03, 0x01, 0x00, 0xa0, 0x32,
- 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
- 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
- 0x05, 0x24, 0x00, 0x10, 0x01,
- 0x04, 0x24, 0x02, 0x06,
- 0x05, 0x24, 0x06, 0x00, 0x01,
- 0x05, 0x24, 0x01, 0x01, 0x01,
- 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
- 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
- 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
- 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
- 0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
- 0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, 0x7E, 0x00,
- 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x01,
- },
- HID: map[uint16][]byte{
- 2: []byte{
- // keyboard and mouse
- 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x85, 0x02, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00,
- 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x06,
- 0x75, 0x08, 0x15, 0x00, 0x25, 0xFF, 0x05, 0x07, 0x19, 0x00, 0x29, 0xFF, 0x81, 0x00, 0xc0, 0x05,
- 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29,
- 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81,
- 0x03, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95,
- 0x03, 0x81, 0x06, 0xc0, 0xc0,
-
- 0x05, 0x0C, // Usage Page (Consumer)
- 0x09, 0x01, // Usage (Consumer Control)
- 0xA1, 0x01, // Collection (Application)
- 0x85, 0x03, // Report ID (3)
- 0x15, 0x00, // Logical Minimum (0)
- 0x26, 0xFF, 0x1F, // Logical Maximum (8191)
- 0x19, 0x00, // Usage Minimum (Unassigned)
- 0x2A, 0xFF, 0x1F, // Usage Maximum (0x1FFF)
- 0x75, 0x10, // Report Size (16)
- 0x95, 0x01, // Report Count (1)
- 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0xC0, // End Collection
- },
- },
-}
-
-var DescriptorCDCMIDI = Descriptor{
- Device: []byte{
- 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
- },
- Configuration: []byte{
- 0x09, 0x02, 0xaf, 0x00, 0x04, 0x01, 0x00, 0xa0, 0x32,
- 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
- 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
- 0x05, 0x24, 0x00, 0x10, 0x01,
- 0x04, 0x24, 0x02, 0x06,
- 0x05, 0x24, 0x06, 0x00, 0x01,
- 0x05, 0x24, 0x01, 0x01, 0x01,
- 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
- 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
- 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
- 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
- 0x08, 0x0b, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00,
- 0x09, 0x04, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
- 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x03,
- 0x09, 0x04, 0x03, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00,
- 0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00,
- 0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
- 0x06, 0x24, 0x02, 0x02, 0x02, 0x00,
- 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
- 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00,
- 0x09, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x25, 0x01, 0x01, 0x01,
- 0x09, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x05, 0x25, 0x01, 0x01, 0x03,
- },
-}
-
-var DescriptorCDCJoystick = Descriptor{
- Device: []byte{
- 0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40,
- 0x41, 0x23, 0x36, 0x80, 0x00, 0x01, 0x01, 0x02,
- 0x03, 0x01,
- },
- Configuration: []byte{
- // Configuration Descriptor Header
- 0x09, 0x02,
- 0x6b, 0x00, // Total Length: 0x006b(107)
- 0x03, 0x01, 0x00, 0xa0, 0xfa,
- // InterfaceAssociation Descriptoy
- 0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
- // InterfaceSescriptor(CDC-Ctrl)
- 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
- // Communication Descriptor
- 0x05, 0x24, 0x00, 0x10, 0x01,
- // Communication Descriptor
- 0x05, 0x24, 0x01, 0x01, 0x01,
- // Communication Descriptor
- 0x04, 0x24, 0x02, 0x06,
- // Communication Descriptor
- 0x05, 0x24, 0x06, 0x00, 0x01,
- // ENDPOINT Descriptor
- 0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x40,
- // InterfaceSescriptor(CDC-Data)
- 0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
- // ENDPOINT Descriptor
- 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
- // ENDPOINT Descriptor
- 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
- // InterfaceSescriptor(HID)
- 0x09, 0x04, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,
- // HID Descriptor
- 0x09, // bLength: 9
- 0x21, // bDescriptorType: 0x21(HID)
- 0x11, 0x01, // bcdHID: 0x111
- 0x00, // bCountryCode: Not Supported
- 0x01, // bNumDescriptors: 1
- 0x22, // Type: HID Report
- 0x00, 0x00, // Length
- // ENDPOINT Descriptor
- 0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x01,
- // ENDPOINT Descriptor
- 0x07, 0x05, 0x05, 0x03, 0x40, 0x00, 0x01,
- },
- HID: map[uint16][]byte{},
-}
diff --git a/src/machine/usb/descriptor/cdc.go b/src/machine/usb/descriptor/cdc.go
new file mode 100644
index 000000000..a44b94aec
--- /dev/null
+++ b/src/machine/usb/descriptor/cdc.go
@@ -0,0 +1,168 @@
+package descriptor
+
+const (
+ cdcFunctionalHeader = 0
+ cdcFunctionalCallManagement = 0x1
+ cdcFunctionalACM = 0x2
+ cdcFunctionalDirect = 0x3
+ cdcFunctionalRinger = 0x4
+ cdcFunctionalCall = 0x5
+ cdcFunctionalUnion = 0x6
+ cdcFunctionalCountry = 0x7
+ cdcFunctionalOperational = 0x8
+ cdcFunctionalUSB = 0x9
+ cdcFunctionalNetwork = 0xa
+ cdcFunctionalProtocol = 0xb
+ cdcFunctionalExtension = 0xc
+ cdcFunctionalMulti = 0xd
+ cdcFunctionalCAPI = 0xe
+ cdcFunctionalEthernet = 0xf
+ cdcFunctionalATM = 0x10
+)
+
+var classSpecificCDCHeader = [classSpecificTypeLen]byte{
+ classSpecificTypeLen,
+ TypeClassSpecific,
+ cdcFunctionalHeader,
+ 0x10, //
+ 0x1, //
+}
+
+var ClassSpecificCDCHeader = ClassSpecificType{
+ data: classSpecificCDCHeader[:],
+}
+
+var classSpecificCDCCallManagement = [classSpecificTypeLen]byte{
+ classSpecificTypeLen,
+ TypeClassSpecific,
+ cdcFunctionalCallManagement,
+ 0x0, //
+ 0x1, //
+}
+
+var ClassSpecificCDCCallManagement = ClassSpecificType{
+ data: classSpecificCDCCallManagement[:],
+}
+
+var classSpecificCDCACM = [classSpecificTypeLen]byte{
+ 4,
+ TypeClassSpecific,
+ cdcFunctionalACM,
+ 0x2, //
+}
+
+var ClassSpecificCDCACM = ClassSpecificType{
+ data: classSpecificCDCACM[:],
+}
+
+var classSpecificCDCUnion = [classSpecificTypeLen]byte{
+ classSpecificTypeLen,
+ TypeClassSpecific,
+ cdcFunctionalUnion,
+ 0x0, //
+ 0x1, //
+}
+
+var ClassSpecificCDCUnion = ClassSpecificType{
+ data: classSpecificCDCUnion[:],
+}
+
+var interfaceAssociationCDC = [interfaceAssociationTypeLen]byte{
+ interfaceAssociationTypeLen,
+ TypeInterfaceAssociation,
+ 0x00, // FirstInterface
+ 0x02, // InterfaceCount
+ 0x02, // FunctionClass
+ 0x02, // FunctionSubClass
+ 0x01, // FunctionProtocol
+ 0x00, // Function
+}
+
+var InterfaceAssociationCDC = InterfaceAssociationType{
+ data: interfaceAssociationCDC[:],
+}
+
+var deviceCDC = [deviceTypeLen]byte{
+ deviceTypeLen,
+ TypeDevice,
+ 0x00, 0x02, // USB version
+ 0xef, // device class
+ 0x02, // device subclass
+ 0x01, // protocol
+ 0x40, // maxpacketsize
+ 0x86, 0x28, // vendor id
+ 0x2d, 0x80, // product id
+ 0x00, 0x01, // device
+ 0x01, // manufacturer
+ 0x02, // product
+ 0x03, // SerialNumber
+ 0x01, // NumConfigurations
+}
+
+var DeviceCDC = DeviceType{
+ data: deviceCDC[:],
+}
+
+var configurationCDC = [configurationTypeLen]byte{
+ configurationTypeLen,
+ TypeConfiguration,
+ 0x4b, 0x00, // adjust length as needed
+ 0x02, // number of interfaces
+ 0x01, // configuration value
+ 0x00, // index to string description
+ 0xa0, // attributes
+ 0x32, // maxpower
+}
+
+var ConfigurationCDC = ConfigurationType{
+ data: configurationCDC[:],
+}
+
+var interfaceCDCControl = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x00, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x01, // NumEndpoints
+ 0x02, // InterfaceClass
+ 0x02, // InterfaceSubClass
+ 0x01, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceCDCControl = InterfaceType{
+ data: interfaceCDCControl[:],
+}
+
+var interfaceCDCData = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x01, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x02, // NumEndpoints
+ 0x0a, // InterfaceClass
+ 0x00, // InterfaceSubClass
+ 0x00, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceCDCData = InterfaceType{
+ data: interfaceCDCData[:],
+}
+
+var CDC = Descriptor{
+ Device: DeviceCDC.Bytes(),
+ Configuration: appendSlices([][]byte{
+ ConfigurationCDC.Bytes(),
+ InterfaceAssociationCDC.Bytes(),
+ InterfaceCDCControl.Bytes(),
+ ClassSpecificCDCHeader.Bytes(),
+ ClassSpecificCDCCallManagement.Bytes(),
+ ClassSpecificCDCACM.Bytes(),
+ ClassSpecificCDCUnion.Bytes(),
+ EndpointEP1IN.Bytes(),
+ InterfaceCDCData.Bytes(),
+ EndpointEP2OUT.Bytes(),
+ EndpointEP3IN.Bytes(),
+ }),
+}
diff --git a/src/machine/usb/descriptor/classspecific.go b/src/machine/usb/descriptor/classspecific.go
new file mode 100644
index 000000000..d8ea937b6
--- /dev/null
+++ b/src/machine/usb/descriptor/classspecific.go
@@ -0,0 +1,17 @@
+package descriptor
+
+const (
+ classSpecificTypeLen = 5
+)
+
+type ClassSpecificType struct {
+ data []byte
+}
+
+func (d ClassSpecificType) Bytes() []byte {
+ return d.data[:d.data[0]]
+}
+
+func (d ClassSpecificType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/configuration.go b/src/machine/usb/descriptor/configuration.go
new file mode 100644
index 000000000..d9446e673
--- /dev/null
+++ b/src/machine/usb/descriptor/configuration.go
@@ -0,0 +1,49 @@
+package descriptor
+
+import (
+ "encoding/binary"
+)
+
+const (
+ configurationTypeLen = 9
+)
+
+type ConfigurationType struct {
+ data []byte
+}
+
+func (d ConfigurationType) Bytes() []byte {
+ return d.data
+}
+
+func (d ConfigurationType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d ConfigurationType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d ConfigurationType) TotalLength(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[2:4], v)
+}
+
+func (d ConfigurationType) NumInterfaces(v uint8) {
+ d.data[4] = byte(v)
+}
+
+func (d ConfigurationType) ConfigurationValue(v uint8) {
+ d.data[5] = byte(v)
+}
+
+func (d ConfigurationType) Configuration(v uint8) {
+ d.data[6] = byte(v)
+}
+
+func (d ConfigurationType) Attributes(v uint8) {
+ d.data[7] = byte(v)
+}
+
+func (d ConfigurationType) MaxPower(v uint8) {
+ d.data[8] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/descriptor.go b/src/machine/usb/descriptor/descriptor.go
new file mode 100644
index 000000000..5b52edb2c
--- /dev/null
+++ b/src/machine/usb/descriptor/descriptor.go
@@ -0,0 +1,63 @@
+package descriptor
+
+import (
+ "runtime/volatile"
+)
+
+const (
+ TypeDevice = 0x1
+ TypeConfiguration = 0x2
+ TypeString = 0x3
+ TypeInterface = 0x4
+ TypeEndpoint = 0x5
+ TypeDeviceQualifier = 0x6
+ TypeInterfaceAssociation = 0xb
+ TypeClassHID = 0x21
+ TypeHIDReport = 0x22
+ TypeClassSpecific = 0x24
+ TypeClassSpecificEndpoint = 0x25
+)
+
+// DeviceDescBank is the USB device endpoint .
+type DeviceDescBank struct {
+ ADDR volatile.Register32
+ PCKSIZE volatile.Register32
+ EXTREG volatile.Register16
+ STATUS_BK volatile.Register8
+ _reserved [5]volatile.Register8
+}
+
+type Device struct {
+ DeviceDescBank [2]DeviceDescBank
+}
+
+type Descriptor struct {
+ Device []byte
+ Configuration []byte
+ HID map[uint16][]byte
+}
+
+func (d *Descriptor) Configure(idVendor, idProduct uint16) {
+ dev := DeviceType{d.Device}
+ dev.VendorID(idVendor)
+ dev.ProductID(idProduct)
+
+ conf := ConfigurationType{d.Configuration}
+ conf.TotalLength(uint16(len(d.Configuration)))
+}
+
+func appendSlices[T any](slices [][]T) []T {
+ var size, pos int
+
+ for _, s := range slices {
+ size += len(s)
+ }
+
+ result := make([]T, size)
+
+ for _, s := range slices {
+ pos += copy(result[pos:], s)
+ }
+
+ return result
+}
diff --git a/src/machine/usb/descriptor/device.go b/src/machine/usb/descriptor/device.go
new file mode 100644
index 000000000..48229fbfd
--- /dev/null
+++ b/src/machine/usb/descriptor/device.go
@@ -0,0 +1,73 @@
+package descriptor
+
+import (
+ "encoding/binary"
+)
+
+const (
+ deviceTypeLen = 18
+)
+
+type DeviceType struct {
+ data []byte
+}
+
+func (d DeviceType) Bytes() []byte {
+ return d.data
+}
+
+func (d DeviceType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d DeviceType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d DeviceType) USB(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[2:4], v)
+}
+
+func (d DeviceType) DeviceClass(v uint8) {
+ d.data[4] = byte(v)
+}
+
+func (d DeviceType) DeviceSubClass(v uint8) {
+ d.data[5] = byte(v)
+}
+
+func (d DeviceType) DeviceProtocol(v uint8) {
+ d.data[6] = byte(v)
+}
+
+func (d DeviceType) MaxPacketSize0(v uint8) {
+ d.data[7] = byte(v)
+}
+
+func (d DeviceType) VendorID(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[8:10], v)
+}
+
+func (d DeviceType) ProductID(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[10:12], v)
+}
+
+func (d DeviceType) Device(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[12:14], v)
+}
+
+func (d DeviceType) Manufacturer(v uint8) {
+ d.data[14] = byte(v)
+}
+
+func (d DeviceType) Product(v uint8) {
+ d.data[15] = byte(v)
+}
+
+func (d DeviceType) SerialNumber(v uint8) {
+ d.data[16] = byte(v)
+}
+
+func (d DeviceType) NumConfigurations(v uint8) {
+ d.data[17] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/endpoint.go b/src/machine/usb/descriptor/endpoint.go
new file mode 100644
index 000000000..affaffa0a
--- /dev/null
+++ b/src/machine/usb/descriptor/endpoint.go
@@ -0,0 +1,111 @@
+package descriptor
+
+import (
+ "encoding/binary"
+)
+
+var endpointEP1IN = [endpointTypeLen]byte{
+ endpointTypeLen,
+ TypeEndpoint,
+ 0x81, // EndpointAddress
+ 0x03, // Attributes
+ 0x10, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x10, // Interval
+}
+
+var EndpointEP1IN = EndpointType{
+ data: endpointEP1IN[:],
+}
+
+var endpointEP2OUT = [endpointTypeLen]byte{
+ endpointTypeLen,
+ TypeEndpoint,
+ 0x02, // EndpointAddress
+ 0x02, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x00, // Interval
+}
+
+var EndpointEP2OUT = EndpointType{
+ data: endpointEP2OUT[:],
+}
+
+var endpointEP3IN = [endpointTypeLen]byte{
+ endpointTypeLen,
+ TypeEndpoint,
+ 0x83, // EndpointAddress
+ 0x02, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x00, // Interval
+}
+
+var EndpointEP3IN = EndpointType{
+ data: endpointEP3IN[:],
+}
+
+var endpointEP4IN = [endpointTypeLen]byte{
+ endpointTypeLen,
+ TypeEndpoint,
+ 0x84, // EndpointAddress
+ 0x03, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x01, // Interval
+}
+
+var EndpointEP4IN = EndpointType{
+ data: endpointEP4IN[:],
+}
+
+var endpointEP5OUT = [endpointTypeLen]byte{
+ endpointTypeLen,
+ TypeEndpoint,
+ 0x05, // EndpointAddress
+ 0x03, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x01, // Interval
+}
+
+var EndpointEP5OUT = EndpointType{
+ data: endpointEP5OUT[:],
+}
+
+const (
+ endpointTypeLen = 7
+)
+
+type EndpointType struct {
+ data []byte
+}
+
+func (d EndpointType) Bytes() []byte {
+ return d.data
+}
+
+func (d EndpointType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d EndpointType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d EndpointType) EndpointAddress(v uint8) {
+ d.data[2] = byte(v)
+}
+
+func (d EndpointType) Attributes(v uint8) {
+ d.data[3] = byte(v)
+}
+
+func (d EndpointType) MaxPacketSize(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[4:6], v)
+}
+
+func (d EndpointType) Interval(v uint8) {
+ d.data[6] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/hid.go b/src/machine/usb/descriptor/hid.go
new file mode 100644
index 000000000..266d10065
--- /dev/null
+++ b/src/machine/usb/descriptor/hid.go
@@ -0,0 +1,189 @@
+package descriptor
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+var configurationCDCHID = [configurationTypeLen]byte{
+ configurationTypeLen,
+ TypeConfiguration,
+ 0x64, 0x00, // adjust length as needed
+ 0x03, // number of interfaces
+ 0x01, // configuration value
+ 0x00, // index to string description
+ 0xa0, // attributes
+ 0x32, // maxpower
+}
+
+var ConfigurationCDCHID = ConfigurationType{
+ data: configurationCDCHID[:],
+}
+
+var interfaceHID = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x02, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x01, // NumEndpoints
+ 0x03, // InterfaceClass
+ 0x00, // InterfaceSubClass
+ 0x00, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceHID = InterfaceType{
+ data: interfaceHID[:],
+}
+
+const (
+ ClassHIDTypeLen = 9
+)
+
+type ClassHIDType struct {
+ data []byte
+}
+
+func (d ClassHIDType) Bytes() []byte {
+ return d.data[:]
+}
+
+func (d ClassHIDType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d ClassHIDType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d ClassHIDType) HID(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[2:4], v)
+}
+
+func (d ClassHIDType) CountryCode(v uint8) {
+ d.data[4] = byte(v)
+}
+
+func (d ClassHIDType) NumDescriptors(v uint8) {
+ d.data[5] = byte(v)
+}
+
+func (d ClassHIDType) ClassType(v uint8) {
+ d.data[6] = byte(v)
+}
+
+func (d ClassHIDType) ClassLength(v uint16) {
+ binary.LittleEndian.PutUint16(d.data[7:9], v)
+}
+
+func FindClassHIDType(data, section []byte) ClassHIDType {
+ idx := bytes.Index(data, section)
+
+ return ClassHIDType{data: data[idx : idx+ClassHIDTypeLen]}
+}
+
+var classHID = [ClassHIDTypeLen]byte{
+ ClassHIDTypeLen,
+ TypeClassHID,
+ 0x11, // HID version L
+ 0x01, // HID version H
+ 0x00, // CountryCode
+ 0x01, // NumDescriptors
+ 0x22, // ClassType
+ 0x7E, // ClassLength L
+ 0x00, // ClassLength H
+}
+
+var ClassHID = ClassHIDType{
+ data: classHID[:],
+}
+
+var CDCHID = Descriptor{
+ Device: DeviceCDC.Bytes(),
+ Configuration: appendSlices([][]byte{
+ ConfigurationCDCHID.Bytes(),
+ InterfaceAssociationCDC.Bytes(),
+ InterfaceCDCControl.Bytes(),
+ ClassSpecificCDCHeader.Bytes(),
+ ClassSpecificCDCACM.Bytes(),
+ ClassSpecificCDCUnion.Bytes(),
+ ClassSpecificCDCCallManagement.Bytes(),
+ EndpointEP1IN.Bytes(),
+ InterfaceCDCData.Bytes(),
+ EndpointEP2OUT.Bytes(),
+ EndpointEP3IN.Bytes(),
+ InterfaceHID.Bytes(),
+ ClassHID.Bytes(),
+ EndpointEP4IN.Bytes(),
+ }),
+ HID: map[uint16][]byte{
+ 2: []byte{
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x06, // Usage (Keyboard)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x02, // Report ID (2)
+ 0x05, 0x07, // Usage Page (KeyCodes)
+ 0x19, 0xe0, // Usage Minimum (224)
+ 0x29, 0xe7, // Usage Maximum (231)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Data, Variable, Absolute), Modifier byte
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x03, //
+ 0x95, 0x06, // Report Count (6)
+ 0x75, 0x08, // Report Size (8)
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0xFF, //
+ 0x05, 0x07, // Usage Page (KeyCodes)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, 0xFF, // Usage Maximum (255)
+ 0x81, 0x00, // Input (Data, Array), Key arrays (6 bytes)
+ 0xc0, // End Collection
+
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x02, // Usage (Mouse)
+ 0xa1, 0x01, // Collection (Application)
+ 0x09, 0x01, // Usage (Pointer)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x85, 0x01, // Report ID (1)
+ 0x05, 0x09, // Usage Page (Buttons)
+ 0x19, 0x01, // Usage Minimum (01)
+ 0x29, 0x03, // Usage Maximun (03)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x95, 0x03, // Report Count (3)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x02, // Input (Data, Variable, Absolute), ;3 button bits
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x05, // Report Size (5)
+ 0x81, 0x03, //
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x09, 0x38, //
+ 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), 2 position bytes (X & Y)
+ 0xc0, // End Collection
+ 0xc0, // End Collection
+
+ 0x05, 0x0C, // Usage Page (Consumer)
+ 0x09, 0x01, // Usage (Consumer Control)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0x03, // Report ID (3)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x1F, // Logical Maximum (8191)
+ 0x19, 0x00, // Usage Minimum (Unassigned)
+ 0x2A, 0xFF, 0x1F, // Usage Maximum (0x1FFF)
+ 0x75, 0x10, // Report Size (16)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+ },
+ },
+}
diff --git a/src/machine/usb/descriptor/interface.go b/src/machine/usb/descriptor/interface.go
new file mode 100644
index 000000000..52f537fea
--- /dev/null
+++ b/src/machine/usb/descriptor/interface.go
@@ -0,0 +1,49 @@
+package descriptor
+
+const (
+ interfaceTypeLen = 9
+)
+
+type InterfaceType struct {
+ data []byte
+}
+
+func (d InterfaceType) Bytes() []byte {
+ return d.data
+}
+
+func (d InterfaceType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d InterfaceType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d InterfaceType) InterfaceNumber(v uint8) {
+ d.data[2] = byte(v)
+}
+
+func (d InterfaceType) AlternateSetting(v uint8) {
+ d.data[3] = byte(v)
+}
+
+func (d InterfaceType) NumEndpoints(v uint8) {
+ d.data[4] = byte(v)
+}
+
+func (d InterfaceType) InterfaceClass(v uint8) {
+ d.data[5] = byte(v)
+}
+
+func (d InterfaceType) InterfaceSubClass(v uint8) {
+ d.data[6] = byte(v)
+}
+
+func (d InterfaceType) InterfaceProtocol(v uint8) {
+ d.data[7] = byte(v)
+}
+
+func (d InterfaceType) Interface(v uint8) {
+ d.data[8] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/interfaceassociation.go b/src/machine/usb/descriptor/interfaceassociation.go
new file mode 100644
index 000000000..f92808626
--- /dev/null
+++ b/src/machine/usb/descriptor/interfaceassociation.go
@@ -0,0 +1,45 @@
+package descriptor
+
+const (
+ interfaceAssociationTypeLen = 8
+)
+
+type InterfaceAssociationType struct {
+ data []byte
+}
+
+func (d InterfaceAssociationType) Bytes() []byte {
+ return d.data
+}
+
+func (d InterfaceAssociationType) Length(v uint8) {
+ d.data[0] = byte(v)
+}
+
+func (d InterfaceAssociationType) Type(v uint8) {
+ d.data[1] = byte(v)
+}
+
+func (d InterfaceAssociationType) FirstInterface(v uint8) {
+ d.data[2] = byte(v)
+}
+
+func (d InterfaceAssociationType) InterfaceCount(v uint8) {
+ d.data[3] = byte(v)
+}
+
+func (d InterfaceAssociationType) FunctionClass(v uint8) {
+ d.data[4] = byte(v)
+}
+
+func (d InterfaceAssociationType) FunctionSubClass(v uint8) {
+ d.data[5] = byte(v)
+}
+
+func (d InterfaceAssociationType) FunctionProtocol(v uint8) {
+ d.data[6] = byte(v)
+}
+
+func (d InterfaceAssociationType) Function(v uint8) {
+ d.data[7] = byte(v)
+}
diff --git a/src/machine/usb/descriptor/joystick.go b/src/machine/usb/descriptor/joystick.go
new file mode 100644
index 000000000..512873b49
--- /dev/null
+++ b/src/machine/usb/descriptor/joystick.go
@@ -0,0 +1,145 @@
+package descriptor
+
+var deviceJoystick = [deviceTypeLen]byte{
+ deviceTypeLen,
+ TypeDevice,
+ 0x00, 0x02, // USB version
+ 0xef, // device class
+ 0x02, // subclass
+ 0x01, // protocol
+ 0x40, // maxpacketsize
+ 0x41, 0x23, // vendor id
+ 0x36, 0x80, // product id
+ 0x00, 0x01, // device
+ 0x01, // manufacturer
+ 0x02, // product
+ 0x03, // SerialNumber
+ 0x01, // NumConfigurations
+}
+
+var DeviceJoystick = DeviceType{
+ data: deviceJoystick[:],
+}
+
+var configurationCDCJoystick = [configurationTypeLen]byte{
+ configurationTypeLen,
+ TypeConfiguration,
+ 0x6b, 0x00, // adjust length as needed
+ 0x03, // number of interfaces
+ 0x01, // configuration value
+ 0x00, // index to string description
+ 0xa0, // attributes
+ 0xfa, // maxpower
+}
+
+var ConfigurationCDCJoystick = ConfigurationType{
+ data: configurationCDCJoystick[:],
+}
+
+var interfaceHIDJoystick = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x02, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x02, // NumEndpoints
+ 0x03, // InterfaceClass
+ 0x00, // InterfaceSubClass
+ 0x00, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceHIDJoystick = InterfaceType{
+ data: interfaceHIDJoystick[:],
+}
+
+var classHIDJoystick = [ClassHIDTypeLen]byte{
+ ClassHIDTypeLen,
+ TypeClassHID,
+ 0x11, // HID version L
+ 0x01, // HID version H
+ 0x00, // CountryCode
+ 0x01, // NumDescriptors
+ 0x22, // ClassType
+ 0x00, // ClassLength L
+ 0x00, // ClassLength H
+}
+
+var ClassHIDJoystick = ClassHIDType{
+ data: classHIDJoystick[:],
+}
+
+var JoystickDefaultHIDReport = []byte{
+ 0x05, 0x01, // Usage page
+ 0x09, 0x04, // Joystick
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x85, 0x01, // REPORT_ID (1)
+ 0x05, 0x09, // USAGE_PAGE (Button)
+ 0x19, 0x01, // USAGE_MINIMUM (Button 1)
+ 0x29, 0x10, // USAGE_MAXIMUM (Button 16)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x95, 0x10, // REPORT_COUNT (16)
+ 0x55, 0x00, // Unit Exponent (-16)
+ 0x65, 0x00, // Unit (0x00)
+ 0x81, 0x02, // INPUT (Data/Var/Abs)
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop Controls)
+ 0x09, 0x39, // USAGE(Hat Switch)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x07, // LOGICAL_MAXIMUM (7)
+ 0x35, 0x00, // PHYSICAL_MINIMUM (0)
+ 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM(315)
+ 0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
+ 0x75, 0x04, // REPORT_SIZE (4)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x02, // INPUT (Data/Var/Abs)
+ 0x09, 0x39, // USAGE(Hat Switch)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x07, // LOGICAL_MAXIMUM (7)
+ 0x35, 0x00, // PHYSICAL_MINIMUM (0)
+ 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM(315)
+ 0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
+ 0x75, 0x04, // REPORT_SIZE (4)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x02, // INPUT (Data/Var/Abs)
+ 0x09, 0x01, // USAGE (Pointer)
+ 0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767)
+ 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
+ 0x75, 0x10, // REPORT_SIZE (16bits)
+ 0x95, 0x06, // REPORT_COUNT (6)
+ 0xa1, 0x00, // COLLECTION (Physical)
+ 0x09, 0x30, // USAGE(X)
+ 0x09, 0x31, // USAGE(Y)
+ 0x09, 0x32, // USAGE(Z)
+ 0x09, 0x33, // USAGE(RX)
+ 0x09, 0x34, // USAGE(RY)
+ 0x09, 0x35, // USAGE(RZ)
+ 0x81, 0x02, // INPUT (Data/Var/Abs)
+ 0xc0, // END_COLLECTION
+ 0xc0, // END_COLLECTION
+}
+
+// CDCJoystick requires that you append the JoystickDescriptor
+// to the Configuration before using. This is in order to support
+// custom configurations.
+var CDCJoystick = Descriptor{
+ Device: DeviceJoystick.Bytes(),
+ Configuration: appendSlices([][]byte{
+ ConfigurationCDCJoystick.Bytes(),
+ InterfaceAssociationCDC.Bytes(),
+ InterfaceCDCControl.Bytes(),
+ ClassSpecificCDCHeader.Bytes(),
+ ClassSpecificCDCACM.Bytes(),
+ ClassSpecificCDCUnion.Bytes(),
+ ClassSpecificCDCCallManagement.Bytes(),
+ EndpointEP1IN.Bytes(),
+ InterfaceCDCData.Bytes(),
+ EndpointEP2OUT.Bytes(),
+ EndpointEP3IN.Bytes(),
+ InterfaceHIDJoystick.Bytes(),
+ ClassHIDJoystick.Bytes(),
+ EndpointEP4IN.Bytes(),
+ EndpointEP5OUT.Bytes(),
+ }),
+ HID: map[uint16][]byte{},
+}
diff --git a/src/machine/usb/descriptor/midi.go b/src/machine/usb/descriptor/midi.go
new file mode 100644
index 000000000..658aec850
--- /dev/null
+++ b/src/machine/usb/descriptor/midi.go
@@ -0,0 +1,249 @@
+package descriptor
+
+var interfaceAssociationMIDI = [interfaceAssociationTypeLen]byte{
+ interfaceAssociationTypeLen,
+ TypeInterfaceAssociation,
+ 0x02, // EndpointAddress
+ 0x02, // Attributes
+ 0x01, // MaxPacketSizeL
+ 0x01, // MaxPacketSizeH
+ 0x00, // Interval
+ 0x00, // Interval
+}
+
+var InterfaceAssociationMIDI = InterfaceAssociationType{
+ data: interfaceAssociationMIDI[:],
+}
+
+var interfaceAudio = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x02, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x00, // NumEndpoints
+ 0x01, // InterfaceClass
+ 0x01, // InterfaceSubClass
+ 0x00, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceAudio = InterfaceType{
+ data: interfaceAudio[:],
+}
+
+var interfaceMIDIStreaming = [interfaceTypeLen]byte{
+ interfaceTypeLen,
+ TypeInterface,
+ 0x03, // InterfaceNumber
+ 0x00, // AlternateSetting
+ 0x02, // NumEndpoints
+ 0x01, // InterfaceClass
+ 0x03, // InterfaceSubClass
+ 0x00, // InterfaceProtocol
+ 0x00, // Interface
+}
+
+var InterfaceMIDIStreaming = InterfaceType{
+ data: interfaceMIDIStreaming[:],
+}
+
+const classSpecificAudioTypeLen = 9
+
+var classSpecificAudioInterface = [classSpecificAudioTypeLen]byte{
+ classSpecificAudioTypeLen,
+ TypeClassSpecific,
+ 0x01,
+ 0x00, //
+ 0x01, //
+ 0x09,
+ 0x00,
+ 0x01,
+ 0x03,
+}
+
+var ClassSpecificAudioInterface = ClassSpecificType{
+ data: classSpecificAudioInterface[:],
+}
+
+const classSpecificMIDIHeaderLen = 7
+
+var classSpecificMIDIHeader = [classSpecificMIDIHeaderLen]byte{
+ classSpecificMIDIHeaderLen,
+ TypeClassSpecific,
+ 0x01,
+ 0x00, //
+ 0x01, //
+ 0x41,
+ 0x00,
+}
+
+var ClassSpecificMIDIHeader = ClassSpecificType{
+ data: classSpecificMIDIHeader[:],
+}
+
+const classSpecificMIDIInJackLen = 6
+
+var classSpecificMIDIInJack1 = [classSpecificMIDIInJackLen]byte{
+ classSpecificMIDIInJackLen,
+ TypeClassSpecific,
+ 0x02, // MIDI In jack
+ 0x01, // Jack type (embedded)
+ 0x01, // Jack ID
+ 0x00, // iJack
+}
+
+var ClassSpecificMIDIInJack1 = ClassSpecificType{
+ data: classSpecificMIDIInJack1[:],
+}
+
+var classSpecificMIDIInJack2 = [classSpecificMIDIInJackLen]byte{
+ classSpecificMIDIInJackLen,
+ TypeClassSpecific,
+ 0x02, // MIDI In jack
+ 0x02, // Jack type (external)
+ 0x02, // Jack ID
+ 0x00, // iJack
+}
+
+var ClassSpecificMIDIInJack2 = ClassSpecificType{
+ data: classSpecificMIDIInJack2[:],
+}
+
+const classSpecificMIDIOutJackLen = 9
+
+var classSpecificMIDIOutJack1 = [classSpecificMIDIOutJackLen]byte{
+ classSpecificMIDIOutJackLen,
+ TypeClassSpecific,
+ 0x03, // MIDI Out jack
+ 0x01, // Jack type (embedded)
+ 0x03, // Jack ID
+ 0x01, // number of input pins
+ 0x02, // source ID
+ 0x01, // source pin
+ 0x00, // iJack
+}
+
+var ClassSpecificMIDIOutJack1 = ClassSpecificType{
+ data: classSpecificMIDIOutJack1[:],
+}
+
+var classSpecificMIDIOutJack2 = [classSpecificMIDIOutJackLen]byte{
+ classSpecificMIDIOutJackLen,
+ TypeClassSpecific,
+ 0x03, // MIDI Out jack
+ 0x02, // Jack type (external)
+ 0x04, // Jack ID
+ 0x01, // number of input pins
+ 0x01, // source ID
+ 0x01, // source pin
+ 0x00, // iJack
+}
+
+var ClassSpecificMIDIOutJack2 = ClassSpecificType{
+ data: classSpecificMIDIOutJack2[:],
+}
+
+const classSpecificMIDIEndpointLen = 5
+
+var classSpecificMIDIOutEndpoint = [classSpecificMIDIEndpointLen]byte{
+ classSpecificMIDIEndpointLen,
+ TypeClassSpecificEndpoint,
+ 0x01, // CS endpoint
+ 0x01, // number MIDI IN jacks
+ 0x01, // assoc Jack ID
+}
+
+var ClassSpecificMIDIOutEndpoint = ClassSpecificType{
+ data: classSpecificMIDIOutEndpoint[:],
+}
+
+var classSpecificMIDIInEndpoint = [classSpecificMIDIEndpointLen]byte{
+ classSpecificMIDIEndpointLen,
+ TypeClassSpecificEndpoint,
+ 0x01, // CS endpoint
+ 0x01, // number MIDI Out jacks
+ 0x03, // assoc Jack ID
+}
+
+var ClassSpecificMIDIInEndpoint = ClassSpecificType{
+ data: classSpecificMIDIInEndpoint[:],
+}
+
+const endpointMIDITypeLen = 9
+
+var endpointEP6IN = [endpointMIDITypeLen]byte{
+ endpointMIDITypeLen,
+ TypeEndpoint,
+ 0x86, // EndpointAddress
+ 0x02, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x00, // Interval
+ 0x00, // refresh
+ 0x00, // sync address
+}
+
+var EndpointEP6IN = EndpointType{
+ data: endpointEP6IN[:],
+}
+
+var endpointEP7OUT = [endpointMIDITypeLen]byte{
+ endpointMIDITypeLen,
+ TypeEndpoint,
+ 0x07, // EndpointAddress
+ 0x02, // Attributes
+ 0x40, // MaxPacketSizeL
+ 0x00, // MaxPacketSizeH
+ 0x00, // Interval
+ 0x00, // refresh
+ 0x00, // sync address
+}
+
+var EndpointEP7OUT = EndpointType{
+ data: endpointEP7OUT[:],
+}
+
+var configurationCDCMIDI = [configurationTypeLen]byte{
+ configurationTypeLen,
+ TypeConfiguration,
+ 0xaf, 0x00, // adjust length as needed
+ 0x04, // number of interfaces
+ 0x01, // configuration value
+ 0x00, // index to string description
+ 0xa0, // attributes
+ 0x32, // maxpower
+}
+
+var ConfigurationCDCMIDI = ConfigurationType{
+ data: configurationCDCMIDI[:],
+}
+
+var CDCMIDI = Descriptor{
+ Device: DeviceCDC.Bytes(),
+ Configuration: appendSlices([][]byte{
+ ConfigurationCDCMIDI.Bytes(),
+ InterfaceAssociationCDC.Bytes(),
+ InterfaceCDCControl.Bytes(),
+ ClassSpecificCDCHeader.Bytes(),
+ ClassSpecificCDCACM.Bytes(),
+ ClassSpecificCDCUnion.Bytes(),
+ ClassSpecificCDCCallManagement.Bytes(),
+ EndpointEP1IN.Bytes(),
+ InterfaceCDCData.Bytes(),
+ EndpointEP2OUT.Bytes(),
+ EndpointEP3IN.Bytes(),
+ InterfaceAssociationMIDI.Bytes(),
+ InterfaceAudio.Bytes(),
+ ClassSpecificAudioInterface.Bytes(),
+ InterfaceMIDIStreaming.Bytes(),
+ ClassSpecificMIDIHeader.Bytes(),
+ ClassSpecificMIDIInJack1.Bytes(),
+ ClassSpecificMIDIInJack2.Bytes(),
+ ClassSpecificMIDIOutJack1.Bytes(),
+ ClassSpecificMIDIOutJack2.Bytes(),
+ EndpointEP7OUT.Bytes(),
+ ClassSpecificMIDIOutEndpoint.Bytes(),
+ EndpointEP6IN.Bytes(),
+ ClassSpecificMIDIInEndpoint.Bytes(),
+ }),
+}
diff --git a/src/machine/usb/hid/joystick/state.go b/src/machine/usb/hid/joystick/state.go
index 51b7e6c40..7cb47a77c 100644
--- a/src/machine/usb/hid/joystick/state.go
+++ b/src/machine/usb/hid/joystick/state.go
@@ -1,6 +1,10 @@
package joystick
-import "encoding/binary"
+import (
+ "machine/usb/descriptor"
+
+ "encoding/binary"
+)
type HatDirection uint8
@@ -159,55 +163,6 @@ func DefaultDefinitions() Definitions {
{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
{MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767},
},
- descriptor: []byte{
- 0x05, 0x01,
- 0x09, 0x04,
- 0xa1, 0x01, // COLLECTION (Application)
- 0x85, 0x01, // REPORT_ID (1)
- 0x05, 0x09, // USAGE_PAGE (Button)
- 0x19, 0x01, // USAGE_MINIMUM (Button 1)
- 0x29, 0x10, // USAGE_MAXIMUM (Button 16)
- 0x15, 0x00, // LOGICAL_MINIMUM (0)
- 0x25, 0x01, // LOGICAL_MAXIMUM (1)
- 0x75, 0x01, // REPORT_SIZE (1)
- 0x95, 0x10, // REPORT_COUNT (16)
- 0x55, 0x00, // Unit Exponent (-16)
- 0x65, 0x00, // Unit (0x00)
- 0x81, 0x02, // INPUT (Data/Var/Abs)
- 0x05, 0x01, // USAGE_PAGE (Generic Desktop Controls)
- 0x09, 0x39, // USAGE(Hat Switch)
- 0x15, 0x00, // LOGICAL_MINIMUM (0)
- 0x25, 0x07, // LOGICAL_MAXIMUM (7)
- 0x35, 0x00, // PHYSICAL_MINIMUM (0)
- 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM(315)
- 0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
- 0x75, 0x04, // REPORT_SIZE (4)
- 0x95, 0x01, // REPORT_COUNT (1)
- 0x81, 0x02, // INPUT (Data/Var/Abs)
- 0x09, 0x39, // USAGE(Hat Switch)
- 0x15, 0x00, // LOGICAL_MINIMUM (0)
- 0x25, 0x07, // LOGICAL_MAXIMUM (7)
- 0x35, 0x00, // PHYSICAL_MINIMUM (0)
- 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM(315)
- 0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
- 0x75, 0x04, // REPORT_SIZE (4)
- 0x95, 0x01, // REPORT_COUNT (1)
- 0x81, 0x02, // INPUT (Data/Var/Abs)
- 0x09, 0x01, // USAGE (Pointer)
- 0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767)
- 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
- 0x75, 0x10, // REPORT_SIZE (16bits)
- 0x95, 0x06, // REPORT_COUNT (6)
- 0xa1, 0x00, // COLLECTION (Physical)
- 0x09, 0x30, // USAGE(X)
- 0x09, 0x31, // USAGE(Y)
- 0x09, 0x32, // USAGE(Z)
- 0x09, 0x33, // USAGE(RX)
- 0x09, 0x34, // USAGE(RY)
- 0x09, 0x35, // USAGE(RZ)
- 0x81, 0x02, // INPUT (Data/Var/Abs)
- 0xc0, // END_COLLECTION
- 0xc0, // END_COLLECTION
- },
+ descriptor: descriptor.JoystickDefaultHIDReport,
}
}
diff --git a/src/machine/usb/usb.go b/src/machine/usb/usb.go
index 97efbbfa4..47a8a3456 100644
--- a/src/machine/usb/usb.go
+++ b/src/machine/usb/usb.go
@@ -23,16 +23,6 @@ const (
ENDPOINT_TYPE_BULK = 0x02
ENDPOINT_TYPE_INTERRUPT = 0x03
- DEVICE_DESCRIPTOR_TYPE = 1
- CONFIGURATION_DESCRIPTOR_TYPE = 2
- STRING_DESCRIPTOR_TYPE = 3
- INTERFACE_DESCRIPTOR_TYPE = 4
- ENDPOINT_DESCRIPTOR_TYPE = 5
- DEVICE_QUALIFIER = 6
- OTHER_SPEED_CONFIGURATION = 7
- SET_REPORT_TYPE = 33
- HID_REPORT_TYPE = 34
-
EndpointOut = 0x00
EndpointIn = 0x80
@@ -51,12 +41,13 @@ const (
SET_INTERFACE = 11
// non standard requests
- GET_REPORT = 1
- GET_IDLE = 2
- GET_PROTOCOL = 3
- SET_REPORT = 9
- SET_IDLE = 10
- SET_PROTOCOL = 11
+ GET_REPORT = 1
+ GET_IDLE = 2
+ GET_PROTOCOL = 3
+ SET_REPORT = 9
+ SET_IDLE = 10
+ SET_PROTOCOL = 11
+ SET_REPORT_TYPE = 33
DEVICE_CLASS_COMMUNICATIONS = 0x02
DEVICE_CLASS_HUMAN_INTERFACE = 0x03