diff --git a/src/machine/machine_mimxrt1062_usb.go b/src/machine/machine_mimxrt1062_usb.go index 696572842..22857351b 100644 --- a/src/machine/machine_mimxrt1062_usb.go +++ b/src/machine/machine_mimxrt1062_usb.go @@ -3,7 +3,7 @@ package machine import ( - "machine/usb2" + "machine/usb" ) // USBCDC is the legacy TinyGo type used to implement USB CDC-ACM device class @@ -13,13 +13,13 @@ import ( // be removed and usb.UART should be used directly instead. type USBCDC struct { port uint8 - uart usb2.UART + uart usb.UART } // Configure the embedded usb.UART with our receiver's settings and the given // UART configuration. This provides compatibility with machine.UART. func (cdc *USBCDC) Configure(config UARTConfig) { - cdc.uart.Configure(usb2.UARTConfig{BaudRate: config.BaudRate}) + cdc.uart.Configure(usb.UARTConfig{BaudRate: config.BaudRate}) } // Buffered returns the number of bytes currently stored in the RX buffer. diff --git a/src/machine/usb/config.go b/src/machine/usb/config.go deleted file mode 100644 index 7663029a3..000000000 --- a/src/machine/usb/config.go +++ /dev/null @@ -1,25 +0,0 @@ -package usb - -// The following constants must be defined for USB 2.0 host/device support. -// -// However, some or all of these constants may be unused in the core driver -// code, depending on which components are allocated by the USB driver. -// -// These values are __PLATFORM-AGNOSTIC__, and they serve two primary roles: -// 1. Aggregate and export values derived from platform-specific constants. -// 2. Configure core attributes defined by the USB 2.0 specification. -// -const ( - // ConfigPortCount defines the number of USB cores supported on this platform. - ConfigPortCount = configDeviceCount + configHostCount -) - -// ConfigDeviceDescriptor defines the fields used to populate host-enumerated -// device descriptors. -type ConfigDeviceDescriptor struct { - Manufacturer string - Product string - VID uint16 - PID uint16 - BCD uint16 -} diff --git a/src/machine/usb/config_mimxrt1062.go b/src/machine/usb/config_mimxrt1062.go deleted file mode 100644 index b14464e1b..000000000 --- a/src/machine/usb/config_mimxrt1062.go +++ /dev/null @@ -1,233 +0,0 @@ -// +build mimxrt1062 - -package usb - -const configCPUFrequencyHz = 600000000 - -// The following constants must be defined for USB 2.0 host/device support. -// -// However, some or all of these constants may be unused in the core driver -// code, depending on which components are allocated by the USB driver. -// -// These values are __PLATFORM-SPECIFIC__, and they serve two primary roles: -// 1. Determine which components to allocate from the USB driver. -// 2. Configure driver attributes NOT defined by the USB 2.0 specification. -// -const ( - // configDeviceCount defines the number of USB device-mode ports available. - configDeviceCount = configDeviceCDCACMCount - - // configHostCount defines the number of USB host-mode ports available. - configHostCount = 0 - - // configInterruptQueueSize defines the number of interrupts to retain in the - // queue of runtime processes. - configInterruptQueueSize = 8 - - // configDeviceBufferSize defines the size of the send and receive data - // endpoint buffers. - configDeviceBufferSize = 512 - - // configDeviceMaxEndpoints defines the maximum number of endpoints supported. - configDeviceMaxEndpoints = 4 - - // configDeviceControllerMaxPacketSize defines the maximum packet size for - // communication with an endpoint. The maximum per USB 2.0 spec is 64 bytes, - // although a platform may restrict this to something lower if needed. - configDeviceControllerMaxPacketSize = 64 - - // configDeviceMaxPower defines the maximum power consumption of the USB - // device when fully-operational, expressed in 2 mA units. - configDeviceMaxPower = 50 // 100 mA - - // configDeviceSelfPowered defines whether the device is self-powered (1) or - // not (0). - configDeviceSelfPowered = 1 - - // configDeviceRemoteWakeup defines whether the device supports remote-wakeup - // (1) or not (0). - configDeviceRemoteWakeup = 0 // (NOT YET SUPPORTED) - - // configDeviceControllerMaxDTD defines the maximum number of DTD supported. - configDeviceControllerMaxDTD = 16 - - // configDeviceControllerQHAlign defines the memory alignment of QH buffer. - // Ensure this agrees with the go:align pragma on deviceControllerQHBuffer. - configDeviceControllerQHAlign = 2048 - - // configDeviceControllerDTDAlign defines the memory alignment of DTD buffer. - // Ensure this agrees with the go:align pragma on deviceControllerDTDBuffer. - configDeviceControllerDTDAlign = 32 -) - -// If USB CDC-ACM device support is required, the following constants must be -// defined. -const ( - // configDeviceCDCACMCount defines the number of USB CDC-ACM interfaces - // to initialize; must be less-than or equal to configDeviceCount. - configDeviceCDCACMCount = 1 - - // configDeviceCDCACMConfigurationCount defines the number of configurations - // required for each CDC-ACM device port. - configDeviceCDCACMConfigurationCount = 1 - - // configDeviceCDCACMConfigurationIndex defines the default configuration - // index used to initialize CDC-ACM device class configurations. This is a - // 1-based index into the list of CDC-ACM configurations (which are 0-based - // slices, and thus this index is offset by -1). A configuration index of 0 - // represents the invalid configuration index. - configDeviceCDCACMConfigurationIndex = 1 - - // configDeviceCDCACMInterfaceCount defines the number of interfaces required - // for each CDC-ACM configuration. - configDeviceCDCACMInterfaceCount = 2 - - // configDeviceCDCACMInterruptInPacketSize defines the packet size of CDC-ACM - // communication interface's interrupt input endpoint. - configDeviceCDCACMInterruptInPacketSize = configDeviceCDCACMFSInterruptInPacketSize // (full-speed) - - // configDeviceCDCACMBulkInPacketSize defines the packet size of CDC-ACM data - // interface's bulk input endpoint. - configDeviceCDCACMBulkInPacketSize = configDeviceCDCACMFSBulkInPacketSize // (full-speed) - - // configDeviceCDCACMBulkOutPacketSize defines the packet size of CDC-ACM data - // interface's bulk output endpoint. - configDeviceCDCACMBulkOutPacketSize = configDeviceCDCACMFSBulkOutPacketSize // (full-speed) - - // configDeviceCDCACMInterruptInInterval defines the interval of CDC-ACM - // communication interface's interrupt input endpoint. - configDeviceCDCACMInterruptInInterval = configDeviceCDCACMFSInterruptInInterval // (full-speed) -) - -// If USB CDC-ACM device support is required, the following arrays must be -// initialized with each device's CDC-ACM configuration. -var ( - // configDeviceCDCACM defines the configuration specific to CDC-ACM devices - // including the properties of endpoints required by the device class driver, - // as well as the serial UART line coding properties. - configDeviceCDCACM = [configDeviceCDCACMCount][configDeviceCDCACMConfigurationCount]deviceCDCACMConfig{ - {{ // USB CDC-ACM [0] - interfaceSpeed: specSpeedFull, // USB full-speed (12 Mbit/s) - // Serial line configuration - lineCodingSize: 7, // Size of line-coding message - lineCodingBaudRate: 115200, // Data terminal rate - lineCodingCharFormat: 0, // Character format - lineCodingParityType: 0, // Parity type - lineCodingDataBits: 8, // Data word size - // Communication/control interface - commInterfaceIndex: descriptorInterfaceCDCACMComm, // communication/control interface index - commInterruptInEndpoint: descriptorEndpointCDCACMCommInterruptIn, // interrupt input endpoint index (address) - commInterruptInPacketSize: configDeviceCDCACMInterruptInPacketSize, - commInterruptInInterval: configDeviceCDCACMInterruptInInterval, - // Data interface - dataInterfaceIndex: descriptorInterfaceCDCACMData, // data interface index - dataBulkInEndpoint: descriptorEndpointCDCACMDataBulkIn, // bulk input endpoint index (address) - dataBulkInPacketSize: configDeviceCDCACMBulkInPacketSize, - dataBulkOutEndpoint: descriptorEndpointCDCACMDataBulkOut, // bulk output endpoint index (address) - dataBulkOutPacketSize: configDeviceCDCACMBulkOutPacketSize, - }}, - } - - // configDeviceCDCACMDescriptor defines the generic USB 2.0 descriptors used - // to describe each CDC-ACM device enabled. - // - // Note that the actual descriptor byte slices need not (should not) be - // defined here. Instead, a reusable global slice should be declared as a - // standalone type and not a member of a composite type; this allows both - // reusability and better control over the memory layout/alignment for USB - // PHYs that may require constraints of this sort. The fields of struct - // deviceDescriptor are therefore all pointers to byte slices so that they - // can be initialized with references to the aforementioned global arrays. - configDeviceCDCACMDescriptor = [configDeviceCDCACMCount]deviceDescriptor{ - { // USB CDC-ACM [0] - pDevice: &descriptorDeviceCDCACM, - pConfig: &descriptorConfigurationCDCACM, - language: []deviceDescriptorLanguage{ - { - pString: []deviceDescriptorString{ - &descriptorStringCDCACMLanguage, - &configDescriptorStringCDCACMManufacturer, - &configDescriptorStringCDCACMProduct, - }, - ident: 0x0409, - }, - }, - }, - } - - // default device descriptor info (little-endian byte order). - configDescriptorDeviceCDCACMVID = []uint8{0xC9, 0x1F} // USB Vendor ID (0x1FC9) - configDescriptorDeviceCDCACMPID = []uint8{0x94, 0x00} // USB Product ID (0x0094) - configDescriptorDeviceCDCACMBCD = []uint8{0x01, 0x01} // USB Device Version (0x0101) - - configDescriptorStringCDCACMManufacturer = []uint8{ - 2 + 2*18, specDescriptorTypeString, - 'N', 0, - 'X', 0, - 'P', 0, - ' ', 0, - 'S', 0, - 'e', 0, - 'm', 0, - 'i', 0, - 'c', 0, - 'o', 0, - 'n', 0, - 'd', 0, - 'u', 0, - 'c', 0, - 't', 0, - 'o', 0, - 'r', 0, - 's', 0, - } - - configDescriptorStringCDCACMProduct = []uint8{ - 2 + 2*20, specDescriptorTypeString, - 'T', 0, - 'i', 0, - 'n', 0, - 'y', 0, - 'G', 0, - 'o', 0, - ' ', 0, - 'U', 0, - 'S', 0, - 'B', 0, - ' ', 0, - '(', 0, - 'C', 0, - 'D', 0, - 'C', 0, - '-', 0, - 'A', 0, - 'C', 0, - 'M', 0, - ')', 0, - } -) - -// The following additional constants are not required by the USB driver but are -// used by the usb package on this platform. -const ( - - // configInterruptPriority defines the priority number for USB interrupts. - configInterruptPriority = 3 - - // configDeviceControllerMaxPrimeAttempts defines the maximum number of - // attempts to prime an endpoint for transfer. If attempts exceeds this - // value, then the endpoint status has been reset. - configDeviceControllerMaxPrimeAttempts = 10000000 - - // USB CDC-ACM high-speed (480 Mbit/s) packet size - configDeviceCDCACMHSInterruptInPacketSize = 16 - configDeviceCDCACMHSInterruptInInterval = 7 // 2^(7-1)/8 = 8ms - configDeviceCDCACMHSBulkInPacketSize = 512 - configDeviceCDCACMHSBulkOutPacketSize = 512 - - // USB CDC-ACM full-speed (12 Mbit/s) packet size - configDeviceCDCACMFSInterruptInPacketSize = 16 - configDeviceCDCACMFSInterruptInInterval = 8 // 2^(8-1)/8 = 16ms - configDeviceCDCACMFSBulkInPacketSize = 64 - configDeviceCDCACMFSBulkOutPacketSize = 64 -) diff --git a/src/machine/usb2/dcd.go b/src/machine/usb/dcd.go similarity index 99% rename from src/machine/usb2/dcd.go rename to src/machine/usb/dcd.go index 2c37dddb4..d6527f9b0 100644 --- a/src/machine/usb2/dcd.go +++ b/src/machine/usb/dcd.go @@ -1,4 +1,4 @@ -package usb2 +package usb import "unsafe" diff --git a/src/machine/usb2/dcd_mimxrt1062.go b/src/machine/usb/dcd_mimxrt1062.go similarity index 99% rename from src/machine/usb2/dcd_mimxrt1062.go rename to src/machine/usb/dcd_mimxrt1062.go index aacd2c322..38aa4ddb0 100644 --- a/src/machine/usb2/dcd_mimxrt1062.go +++ b/src/machine/usb/dcd_mimxrt1062.go @@ -1,6 +1,6 @@ // +build mimxrt1062 -package usb2 +package usb // Implementation of USB device controller interface (dcd) for NXP iMXRT1062. diff --git a/src/machine/usb2/desc.go b/src/machine/usb/desc.go similarity index 99% rename from src/machine/usb2/desc.go rename to src/machine/usb/desc.go index 1b0858f70..92bc22375 100644 --- a/src/machine/usb2/desc.go +++ b/src/machine/usb/desc.go @@ -1,4 +1,4 @@ -package usb2 +package usb const descUSBSpecVersion = uint16(0x0200) // USB 2.0 diff --git a/src/machine/usb2/desc_mimxrt1062.go b/src/machine/usb/desc_mimxrt1062.go similarity index 99% rename from src/machine/usb2/desc_mimxrt1062.go rename to src/machine/usb/desc_mimxrt1062.go index 91b1a8935..1b0108888 100644 --- a/src/machine/usb2/desc_mimxrt1062.go +++ b/src/machine/usb/desc_mimxrt1062.go @@ -1,6 +1,6 @@ // +build mimxrt1062 -package usb2 +package usb // descCPUFrequencyHz defines the target CPU frequency (Hz). const descCPUFrequencyHz = 600000000 diff --git a/src/machine/usb/descriptor.go b/src/machine/usb/descriptor.go deleted file mode 100644 index 51f0ad82f..000000000 --- a/src/machine/usb/descriptor.go +++ /dev/null @@ -1,162 +0,0 @@ -package usb - -// USB specification version number (BCD) -var descriptorUSBSpecification = []uint8{0x00, 0x02} // USB 2.0 - -// USB CDC-ACM descriptor constants -const ( - // interface indices - descriptorInterfaceCDCACMComm = 0 // communication/control interface - descriptorInterfaceCDCACMData = 1 // data interface - - descriptorEndpointCDCACMCommInterruptIn = 1 // interrupt endpoint (input) - descriptorEndpointCDCACMDataBulkIn = 2 // data endpoint (input) - descriptorEndpointCDCACMDataBulkOut = 3 // data endpoint (output) - - descriptorConfigurationCDCACMHeaderFuncSize = 5 - descriptorConfigurationCDCACMCallManageSize = 5 - descriptorConfigurationCDCACMAbstractSize = 4 - descriptorConfigurationCDCACMUnionFuncSize = 5 - - descriptorConfigurationCDCACMSize = uint16( - specDescriptorLengthConfigure + // configuration - specDescriptorLengthInterface + // communication/control interface - descriptorConfigurationCDCACMHeaderFuncSize + // CDC header - descriptorConfigurationCDCACMCallManageSize + // CDC call management - descriptorConfigurationCDCACMAbstractSize + // CDC abstract control - descriptorConfigurationCDCACMUnionFuncSize + // CDC union - specDescriptorLengthEndpoint + // communication/control input endpoint - specDescriptorLengthInterface + // data interface - specDescriptorLengthEndpoint + // data input endpoint - specDescriptorLengthEndpoint) // data output endpoint - - descriptorConfigurationCDCACMAttributes = (specDescriptorConfigureAttributeD7Msk) | // Bit 7: reserved (1) - (configDeviceSelfPowered << specDescriptorConfigureAttributeSelfPoweredPos) | // Bit 6: self-powered - (configDeviceRemoteWakeup << specDescriptorConfigureAttributeRemoteWakeupPos) | // Bit 5: remote wakeup - 0 // Bits 0-4: reserved (0) -) - -// USB 2.0 CDC-ACM descriptors -var ( - // descriptorDeviceCDCACM is the default device descriptor for CDC-ACM - // devices. - descriptorDeviceCDCACM = []uint8{ - specDescriptorLengthDevice, // Size of this descriptor in bytes - specDescriptorTypeDevice, // DEVICE Descriptor Type - descriptorUSBSpecification[0], // USB Specification Release Number in BCD (low) - descriptorUSBSpecification[1], // USB Specification Release Number in BCD (high) - uint8(deviceClassCDC), // Class code (assigned by the USB-IF). - 0, // Subclass code (assigned by the USB-IF). - deviceCDCNoClassSpecificProtocol, // Protocol code (assigned by the USB-IF). - configDeviceControllerMaxPacketSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64) - configDescriptorDeviceCDCACMVID[0], // Vendor ID (low) (assigned by the USB-IF) - configDescriptorDeviceCDCACMVID[1], // Vendor ID (high) (assigned by the USB-IF) - configDescriptorDeviceCDCACMPID[0], // Product ID (low) (assigned by the manufacturer) - configDescriptorDeviceCDCACMPID[1], // Product ID (high) (assigned by the manufacturer) - configDescriptorDeviceCDCACMBCD[0], // Device release number in BCD (low) - configDescriptorDeviceCDCACMBCD[1], // Device release number in BCD (high) - 0x01, // Index of string descriptor describing manufacturer - 0x02, // Index of string descriptor describing product - 0x00, // Index of string descriptor describing the device's serial number - configDeviceCDCACMConfigurationCount, // Number of possible configurations - } - - // descriptorConfigurationCDCACM is the default configuration descriptor for - // CDC-ACM devices. - descriptorConfigurationCDCACM = []uint8{ - specDescriptorLengthConfigure, // Size of this descriptor in bytes - specDescriptorTypeConfigure, // Descriptor Type - uint8(descriptorConfigurationCDCACMSize), // Total length of data returned for this configuration (low) - uint8(descriptorConfigurationCDCACMSize >> 8), // Total length of data returned for this configuration (high) - configDeviceCDCACMInterfaceCount, // Number of interfaces supported by this configuration - configDeviceCDCACMConfigurationIndex, // Value to use to select this configuration - 0, // Index of string descriptor describing this configuration - descriptorConfigurationCDCACMAttributes, // Configuration attributes - configDeviceMaxPower, // Max power consumption when fully-operational (2 mA units) - - // Communication/Control Interface Descriptor - specDescriptorLengthInterface, // Descriptor length - specDescriptorTypeInterface, // Descriptor type - descriptorInterfaceCDCACMComm, // Interface index - 0, // Alternate setting - 1, // Number of endpoints - deviceCDCCommClass, // Class code - deviceCDCAbstractControlModel, // Subclass code - deviceCDCNoClassSpecificProtocol, // Protocol code (NOTE: Teensyduino defines this as 1 [AT V.250]) - 0, // Interface Description String Index - - // CDC Header Functional Descriptor - descriptorConfigurationCDCACMHeaderFuncSize, // Size of this descriptor in bytes - specDescriptorTypeCDCInterface, // Descriptor Type - deviceCDCHeaderFuncDesc, // Descriptor Subtype - 0x10, // USB CDC specification version 1.10 (low) - 0x01, // USB CDC specification version 1.10 (high) - - // CDC Call Management Functional Descriptor - descriptorConfigurationCDCACMCallManageSize, // Size of this descriptor in bytes - specDescriptorTypeCDCInterface, // Descriptor Type - deviceCDCCallManagementFuncDesc, // Descriptor Subtype - 0x01, // Capabilities - 1, // Data Interface - - // CDC Abstract Control Management Functional Descriptor - descriptorConfigurationCDCACMAbstractSize, // Size of this descriptor in bytes - specDescriptorTypeCDCInterface, // Descriptor Type - deviceCDCAbstractControlFuncDesc, // Descriptor Subtype - 0x06, // Capabilities - - // CDC Union Functional Descriptor - descriptorConfigurationCDCACMUnionFuncSize, // Size of this descriptor in bytes - specDescriptorTypeCDCInterface, // Descriptor Type - deviceCDCUnionFuncDesc, // Descriptor Subtype - 0, // Controlling interface index - 1, // Controlled interface index - - // Communication/Control Notification Endpoint descriptor - specDescriptorLengthEndpoint, // Size of this descriptor in bytes - specDescriptorTypeEndpoint, // Descriptor Type - descriptorEndpointCDCACMCommInterruptIn | // Endpoint address - specDescriptorEndpointAddressDirectionIn, - uint8(specEndpointInterrupt), // Attributes - uint8(configDeviceCDCACMInterruptInPacketSize), // Max packet size (low) - uint8(configDeviceCDCACMInterruptInPacketSize >> 8), // Max packet size (high) - configDeviceCDCACMInterruptInInterval, // Polling Interval - - // Data Interface Descriptor - specDescriptorLengthInterface, // Interface length - specDescriptorTypeInterface, // Interface type - descriptorInterfaceCDCACMData, // Interface index - 0, // Alternate setting - 2, // Number of endpoints - deviceCDCDataClass, // Class code - 0, // Subclass code - deviceCDCNoClassSpecificProtocol, // Protocol code - 0, // Interface Description String Index - - // Data Bulk Input Endpoint descriptor - specDescriptorLengthEndpoint, // Size of this descriptor in bytes - specDescriptorTypeEndpoint, // Descriptor Type - descriptorEndpointCDCACMDataBulkIn | // Endpoint address - specDescriptorEndpointAddressDirectionIn, - uint8(specEndpointBulk), // Attributes - uint8(configDeviceCDCACMBulkInPacketSize), // Max packet size (low) - uint8(configDeviceCDCACMBulkInPacketSize >> 8), // Max packet size (high) - 0, // Polling Interval - - // Data Bulk Output Endpoint descriptor - specDescriptorLengthEndpoint, // Size of this descriptor in bytes - specDescriptorTypeEndpoint, // Descriptor Type - descriptorEndpointCDCACMDataBulkOut | // Endpoint address - specDescriptorEndpointAddressDirectionOut, - uint8(specEndpointBulk), // Attributes - uint8(configDeviceCDCACMBulkOutPacketSize), // Max packet size (low) - uint8(configDeviceCDCACMBulkOutPacketSize >> 8), // Max packet size (high) - 0, // Polling Interval - } - - descriptorStringCDCACMLanguage = []uint8{ - 2 + 2*1, // Size of this descriptor in bytes - specDescriptorTypeString, - 0x09, 0x04, - } -) diff --git a/src/machine/usb/device.go b/src/machine/usb/device.go deleted file mode 100644 index ce853190f..000000000 --- a/src/machine/usb/device.go +++ /dev/null @@ -1,1066 +0,0 @@ -package usb - -// Unexported USB device type definitions. -type ( - // deviceClassDriver defines the class driver interface. - // - // This interface is used internally to abstract communication between a USB - // device and the device class (e.g., CDC, HID, MSC, etc.) in which it is - // configured. - deviceClassDriver interface { - init(device *device, config *deviceClassConfig, id uint8) status // Class driver initialization- entry of the class driver - deinit() status // Class driver de-initialization - event(event deviceClassEventID, param interface{}) status // Class driver event callback - send(ep uint8, buffer []uint8, length uint32) status // Class driver send to endpoint - receive(ep uint8, buffer []uint8, length uint32) status // Class driver receive from endpoint - } - - // deviceClassEventHandler defines the methods required to receive all device- - // and class-level event notifications on a given USB port. - // - // This interface is intended as the primary communication mechanism between - // a USB device (of any class) and the application layer using that device. - // Thus, it is meant to be implemented internally by one of the application's - // USB handlers (e.g., a serial UART driver using the CDC-ACM device class). - deviceClassEventHandler interface { - deviceEvent(ev deviceEventID, param interface{}) status - classEvent(ev uint32, param interface{}) status - } - - // deviceEndpointController defines the method(s) required - deviceEndpointController interface { - controlEndpoint(message deviceEndpointControlMessage, param interface{}) status - } - - deviceEventFunc func(ev deviceEventID, param interface{}) status - deviceRequestCallbackFunc func(setup *deviceSetup, buffer *[]uint8, length *uint32) status - - deviceNotificationID uint8 - deviceControlID uint8 - deviceStatusID uint8 - deviceStateID uint8 - deviceEndpointStatusID uint8 - deviceClassEventID uint8 - deviceEventID uint8 - deviceClassID uint8 - deviceControlRWSequence uint8 - - deviceDescriptorString *[]uint8 - - deviceDescriptorLanguage struct { - pString []deviceDescriptorString - ident uint16 - } - - deviceDescriptor struct { - pDevice *[]uint8 - pConfig *[]uint8 - language []deviceDescriptorLanguage - } - - deviceEndpointConfig struct { - maxPacketSize uint16 // Endpoint maximum packet size - address uint8 // Endpoint address - transferType uint8 // Endpoint transfer type - zlt uint8 // ZLT flag - interval uint8 // Endpoint interval - } - - deviceEndpointStatus struct { - address uint8 // Endpoint address - status uint16 // Endpoint status (idle or stalled) - } - - deviceNotification struct { - buffer []uint8 // Transferred buffer - length uint32 // Transferred data length - code deviceNotificationID // Notification code - isSetup bool // Is in a setup phase - } - - // deviceSetup contains the setup information for a USB device. - deviceSetupBitmap uint64 - deviceSetupBuffer [deviceSetupSize]uint8 - deviceSetup struct { - bmRequestType uint8 // 8, 1 (bits, bytes) - bRequest uint8 // 8, 1 - wValue uint16 // 16, 2 - wIndex uint16 // 16, 2 - wLength uint16 // 16, 2 (= 64 bits, 8 bytes) - } - - deviceEndpointControlMessage struct { - buffer []uint8 // Transferred buffer - length uint32 // Transferred data length - isSetup bool // Is in a setup phase - } - - deviceEndpointControlList [2 * configDeviceMaxEndpoints]deviceEndpointControl - deviceEndpointControl struct { - handler deviceEndpointController - param interface{} // Parameter for callback function - isBusy bool - } - - // deviceEndpoint contains the information for a USB device endpoint. - deviceEndpoint struct { - address uint8 // Endpoint address - transferType uint8 // Endpoint transfer type - maxPacketSize uint16 // Endpoint maximum packet size - interval uint8 // Endpoint interval - } - - // deviceInterface contains the endpoints and class-specific information for - // a USB device interface. - deviceInterface struct { - alternateSetting uint8 // Alternate setting number - endpoint []deviceEndpoint // Endpoints of the interface - classSpecific interface{} // Class specific structure handle - } - - // deviceClassInterface contains the USB device class details, including - // all of its device interfaces. - deviceClassInterface struct { - classCode uint8 // Class code of the interface - subclassCode uint8 // Subclass code of the interface - protocolCode uint8 // Protocol code of the interface - interfaceNumber uint8 // Interface number - deviceInterface []deviceInterface // Interface structure list - } - - // deviceClassInfo contains the USB device class ID and all of its class - // interfaces. - deviceClassInfo struct { - classID deviceClassID // Class type - interfaceList []deviceClassInterface // Interfaces of the class - } - - // deviceClassConfig contains the configuration for a USB device class. - deviceClassConfig struct { - driver deviceClassDriver // USB device class driver interface - info deviceClassInfo // Detailed information of the class - } - - // deviceClass contains common device class state information. - deviceClass struct { - device *device // USB device handle - config []deviceClassConfig // USB device class configuration list - handler deviceClassEventHandler // application callback - setupBuffer []uint8 // Setup packet data buffer - transcationBuffer uint16 // Get status/configuration, get/set interface, get sync frame - } - - device struct { - port uint8 // USB port (core index) - controller deviceController // Controller interface - class *deviceClass // USB device class - endpointControl deviceEndpointControlList // Endpoint callback function structure - deviceAddress uint8 // Current device address - state deviceStateID // Current device state - isResetting bool // Is doing device reset or not - hwTick int64 // (volatile) Current hw tick (ms) - } - - // // This structure is used to pass the control request information. - // // The structure is used in following two cases. - // // 1. Case one, the host wants to send data to the device in the control data stage: @n - // // a. If a setup packet is received, the structure is used to pass the setup packet data and wants to get the - // // buffer to receive data sent from the host. - // // The field isSetup is 1. - // // The length is the requested buffer length. - // // The buffer is filled by the class or application by using the valid buffer address. - // // The setup is the setup packet address. - // // b. If the data received is sent by the host, the structure is used to pass the data buffer address and the - // // data - // // length sent by the host. - // // In this way, the field isSetup is 0. - // // The buffer is the address of the data sent from the host. - // // The length is the received data length. - // // The setup is the setup packet address. @n - // // 2. Case two, the host wants to get data from the device in control data stage: @n - // // If the setup packet is received, the structure is used to pass the setup packet data and wants to get the - // // data buffer address to send data to the host. - // // The field isSetup is 1. - // // The length is the requested data length. - // // The buffer is filled by the class or application by using the valid buffer address. - // // The setup is the setup packet address. - deviceControlRequest struct { - setup deviceSetup // Setup data - buffer []uint8 // Buffer - length uint32 // Buffer length or requested length - isSetup bool // Indicates whether a setup packet is received - } - - // // deviceGetDescriptorCommon contains the result of a control request for: - // // get descriptor common - // deviceGetDescriptorCommon struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // } - - // deviceGetDeviceDescriptor contains the result of a control request for: - // get device descriptor - deviceGetDeviceDescriptor struct { - buffer []uint8 // Buffer - length uint32 // Buffer length - } - - // // deviceGetDeviceQualifierDescriptor contains the result of a control - // // request for: get device qualifier descriptor - // deviceGetDeviceQualifierDescriptor struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // } - - // deviceGetConfigurationDescriptor contains the result of a control request - // for: get configuration descriptor - deviceGetConfigurationDescriptor struct { - buffer []uint8 // Buffer - length uint32 // Buffer length - configuration uint8 // The configuration number - } - - // // deviceGetBOSDescriptor contains the result of a control request for: get - // // bos descriptor - // deviceGetBOSDescriptor struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // } - - // deviceGetStringDescriptor contains the result of a control request for: - // get string descriptor - deviceGetStringDescriptor struct { - buffer []uint8 // Buffer - length uint32 // Buffer length - languageID uint16 // Language ID - stringIndex uint8 // String index - } - - // // deviceGetHIDDescriptor contains the result of a control request for: get - // // HID descriptor - // deviceGetHIDDescriptor struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // interfaceNumber uint8 // The interface number - // } - - // // deviceGetHIDReportDescriptor contains the result of a control request for: - // // get HID report descriptor - // deviceGetHIDReportDescriptor struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // interfaceNumber uint8 // The interface number - // } - - // // deviceGetHIDPhysicalDescriptor contains the result of a control request - // // for: get HID physical descriptor - // deviceGetHIDPhysicalDescriptor struct { - // buffer []uint8 // Buffer - // length uint32 // Buffer length - // index uint8 // Physical index - // interfaceNumber uint8 // The interface number - // } - -) - -// Unexported enumerated constant values for USB device. -const ( - deviceNotifyBusReset deviceNotificationID = iota + 0x10 // Reset signal detected - deviceNotifySuspend // Suspend signal detected - deviceNotifyResume // Resume signal detected - deviceNotifyLPMSleep // LPM signal detected - deviceNotifyLPMResume // Resume signal detected - deviceNotifyError // Errors happened in bus - deviceNotifyDetach // Device disconnected from a host - deviceNotifyAttach // Device connected to a host - deviceNotifyDCDDetectFinished // Device charger detection finished -) - -const ( - deviceControlRun deviceControlID = iota // Enable the device functionality - deviceControlStop // Disable the device functionality - deviceControlEndpointInit // Initialize a specified endpoint - deviceControlEndpointDeinit // De-initialize a specified endpoint - deviceControlEndpointStall // Stall a specified endpoint - deviceControlEndpointUnstall // Un-stall a specified endpoint - deviceControlGetDeviceStatus // Get device status - deviceControlGetEndpointStatus // Get endpoint status - deviceControlSetDeviceAddress // Set device address - deviceControlGetSynchFrame // Get current frame - deviceControlResume // Drive controller to generate a resume signal in USB bus - deviceControlSleepResume // Drive controller to generate a LPM resume signal in USB bus - deviceControlSuspend // Drive controller to enter into suspend mode - deviceControlSleep // Drive controller to enter into sleep mode - deviceControlSetDefaultStatus // Set controller to default status - deviceControlGetSpeed // Get current speed - deviceControlGetOTGStatus // Get OTG status - deviceControlSetOTGStatus // Set OTG status - deviceControlSetTestMode // Drive xCHI into test mode - deviceControlGetRemoteWakeUp // Get flag of LPM Remote Wake-up Enabled by USB host. - deviceControlDCDDisable // disable dcd module function. - deviceControlDCDEnable // enable dcd module function. - deviceControlPreSetDeviceAddress // Pre set device address - deviceControlUpdateHwTick // update hardware tick -) - -const ( - deviceStatusTestMode deviceStatusID = iota + 1 // Test mode - deviceStatusSpeed // Current speed - deviceStatusOTG // OTG status - deviceStatusDevice // Device status - deviceStatusEndpoint // Endpoint state usb_device_endpoint_status_t - deviceStatusDeviceState // Device state - deviceStatusAddress // Device address - deviceStatusSynchFrame // Current frame - deviceStatusBus // Bus status - deviceStatusBusSuspend // Bus suspend - deviceStatusBusSleep // Bus suspend - deviceStatusBusResume // Bus resume - deviceStatusRemoteWakeup // Remote wakeup state - deviceStatusBusSleepResume // Bus resume -) - -const ( - deviceStateConfigured deviceStateID = iota // Device state, Configured - deviceStateAddress // Device state, Address - deviceStateDefault // Device state, Default - deviceStateAddressing // Device state, Address setting - deviceStateTestMode // Device state, Test mode - deviceStateInit // Device state, initializing -) - -const ( - deviceEndpointStateIdle deviceEndpointStatusID = iota // Endpoint state, idle - deviceEndpointStateStalled // Endpoint state, stalled -) - -const ( - deviceEventBusReset deviceEventID = iota + 1 // USB bus reset signal detected - deviceEventSuspend // USB bus suspend signal detected - deviceEventResume // USB bus resume signal detected. The resume signal is driven by itself or a host - deviceEventSleeped // USB bus LPM suspend signal detected - deviceEventLPMResume // USB bus LPM resume signal detected. The resume signal is driven by itself or a host - deviceEventError // An error is happened in the bus. - deviceEventDetach // USB device is disconnected from a host. - deviceEventAttach // USB device is connected to a host. - deviceEventSetConfiguration // Set configuration. - deviceEventSetInterface // Set interface. - deviceEventGetDeviceDescriptor // Get device descriptor. - deviceEventGetConfigurationDescriptor // Get configuration descriptor. - deviceEventGetStringDescriptor // Get string descriptor. - deviceEventGetHIDDescriptor // Get HID descriptor. - deviceEventGetHIDReportDescriptor // Get HID report descriptor. - deviceEventGetHIDPhysicalDescriptor // Get HID physical descriptor. - deviceEventGetBOSDescriptor // Get configuration descriptor. - deviceEventGetDeviceQualifierDescriptor // Get device qualifier descriptor. - deviceEventVendorRequest // Vendor request. - deviceEventSetRemoteWakeup // Enable or disable remote wakeup function. - deviceEventGetConfiguration // Get current configuration index - deviceEventGetInterface // Get current interface alternate setting value - deviceEventSetBHNPEnable // Enable or disable BHNP. - deviceEventDCDDetectionfinished // The DCD detection finished -) - -const ( - deviceClassInvalid deviceClassID = iota - deviceClassHID - deviceClassCDC - deviceClassMSC - deviceClassAudio - deviceClassPHDC - deviceClassVideo - deviceClassPrinter - deviceClassDFU - deviceClassCCID -) - -const ( - deviceClassEventInvalid deviceClassEventID = iota - deviceClassEventClassRequest - deviceClassEventDeviceReset - deviceClassEventSetConfiguration - deviceClassEventSetInterface - deviceClassEventSetEndpointHalt - deviceClassEventClearEndpointHalt -) - -const ( - deviceControlPipeSetupStage deviceControlRWSequence = iota // Setup stage - deviceControlPipeDataStage // Data stage - deviceControlPipeStatusStage // status stage -) - -// Sizes of various device structures and buffers. -const ( - deviceSetupSize = 8 // deviceSetup struct (bytes) -) - -var ( - deviceClassInstance [configDeviceCount]deviceClass - deviceSetupBufferInstance [configDeviceCount]deviceSetupBuffer - - deviceEndpointControlInConfig = deviceEndpointConfig{ - maxPacketSize: configDeviceControllerMaxPacketSize, - address: uint8(specEndpointControl | specDescriptorEndpointAddressDirectionIn), - transferType: specEndpointControl, - zlt: 1, - interval: 0, - } - deviceEndpointControlOutConfig = deviceEndpointConfig{ - maxPacketSize: configDeviceControllerMaxPacketSize, - address: uint8(specEndpointControl | specDescriptorEndpointAddressDirectionOut), - transferType: specEndpointControl, - zlt: 1, - interval: 0, - } -) - -func (d *device) init(port uint8) (s status) { - - // initialize device - d.port = port - d.controller = d.initController() // obtain a device controller handle - d.deviceAddress = 0 - d.state = deviceStateDefault - d.isResetting = false - d.hwTick = 0 - for i := range d.endpointControl { - d.endpointControl[i].handler = nil - d.endpointControl[i].param = nil - d.endpointControl[i].isBusy = false - } - - // initialize platform via device controller interface - return d.controller.init() -} - -func (d *device) deinit() status { - - // de=initialize device - s := d.controller.deinit() - d.controller = nil - return s -} - -func (d *device) initClass(id uint8, config []deviceClassConfig, - handler deviceClassEventHandler) *deviceClass { - - // verify a device configuration was provided - if nil == d || nil == config || len(config) == 0 { - return nil - } - - if 0 == id || int(id) > len(config) { - return nil - } - - c := &deviceClassInstance[d.port] - b := &deviceSetupBufferInstance[d.port] - - // initialize device class - c.device = d - c.config = config - c.handler = handler - c.setupBuffer = b[:] - c.transcationBuffer = 0 - - // add a class reference to the receiver - d.class = c - - // initialze each of the device class drivers - for i := range c.config { - if nil != c.config[i].driver { - if !c.config[i].driver.init(d, &c.config[i], id).OK() { - // remove the driver from configuration if it fails initialization - c.config[i].driver = nil - } - } - } - - return c -} - -func (d *device) transfer(address uint8, buffer []uint8, length uint32) status { - - if nil == d.controller { - return statusInvalidController - } - - endpoint, direction := unpackEndpoint(address) - index := (endpoint << 1) | direction - - if d.endpointControl[index].isBusy { - return statusBusy - } - d.endpointControl[index].isBusy = true - - var s status - if specDescriptorEndpointAddressDirectionIn == - address&specDescriptorEndpointAddressDirectionMsk { - s = d.controller.send(address, buffer, length) - } else { - s = d.controller.receive(address, buffer, length) - } - if !s.OK() { - d.endpointControl[index].isBusy = false - } - return s -} - -func (d *device) send(address uint8, buffer []uint8, length uint32) status { - return d.transfer((address&specDescriptorEndpointAddressNumberMsk)| - (specDescriptorEndpointAddressDirectionIn), buffer, length) -} - -func (d *device) receive(address uint8, buffer []uint8, length uint32) status { - return d.transfer((address&specDescriptorEndpointAddressNumberMsk)| - (specDescriptorEndpointAddressDirectionOut), buffer, length) -} - -func (d *device) cancel(address uint8) status { - if nil == d.controller { - return statusInvalidController - } - return d.controller.cancel(address) -} - -func (d *device) control(command deviceControlID, param interface{}) status { - if nil == d.controller { - return statusInvalidController - } - return d.controller.control(command, param) -} - -func (d *device) initControlPipes() status { - - if s := d.initEndpoint(&deviceEndpointControlInConfig, d, d.class); !s.OK() { - return s - } - - if s := d.initEndpoint(&deviceEndpointControlOutConfig, d, d.class); !s.OK() { - _ = d.deinitEndpoint(deviceEndpointControlInConfig.address) - return s - } - - return statusSuccess -} - -func (d *device) initEndpoint(config *deviceEndpointConfig, - handler deviceEndpointController, param interface{}) status { - - endpoint, direction := unpackEndpoint(config.address) - - if endpoint >= configDeviceMaxEndpoints { - return statusInvalidParameter - } - - d.endpointControl[(endpoint<<1)|direction].handler = handler - d.endpointControl[(endpoint<<1)|direction].param = param - d.endpointControl[(endpoint<<1)|direction].isBusy = false - - return d.control(deviceControlEndpointInit, config) -} - -func (d *device) deinitEndpoint(address uint8) status { - - s := d.control(deviceControlEndpointDeinit, address) - - endpoint, direction := unpackEndpoint(address) - - if endpoint >= configDeviceMaxEndpoints { - return statusInvalidParameter - } - - d.endpointControl[(endpoint<<1)|direction].handler = nil - d.endpointControl[(endpoint<<1)|direction].param = nil - d.endpointControl[(endpoint<<1)|direction].isBusy = false - - return s -} - -func (d *device) stallEndpoint(address uint8) status { - - endpoint, _ := unpackEndpoint(address) - - if endpoint >= configDeviceMaxEndpoints { - return statusInvalidParameter - } - return d.control(deviceControlEndpointStall, address) -} - -func (d *device) unstallEndpoint(address uint8) status { - - endpoint, _ := unpackEndpoint(address) - - if endpoint >= configDeviceMaxEndpoints { - return statusInvalidParameter - } - return d.control(deviceControlEndpointUnstall, address) -} - -func (d *device) feedback(setup *deviceSetup, status status, stage deviceControlRWSequence, - buffer *[]uint8, length *uint32) status { - direction := uint8(specIn) - if !status.OK() { - if (setup.bmRequestType&specRequestTypeTypeMsk) == specRequestTypeTypeStandard && - (setup.bmRequestType&specRequestTypeDirMsk) == specRequestTypeDirOut && - 0 != setup.wLength && deviceControlPipeSetupStage == stage { - direction = specOut - } - return d.stallEndpoint(specEndpointControl | - (direction << specDescriptorEndpointAddressDirectionPos)) - } else { - if *length > uint32(setup.wLength) { - *length = uint32(setup.wLength) - } - s := d.send(specEndpointControl, *buffer, *length) - if s.OK() && (setup.bmRequestType&specRequestTypeDirMsk) == specRequestTypeDirIn { - s = d.receive(specEndpointControl, nil, 0) - } - return s - } -} - -func (d *device) controlEndpoint(message deviceEndpointControlMessage, param interface{}) status { - - // verify request and parameters - if message.length == 0xFFFFFFFF || nil == param { - return statusInvalidRequest - } - class, ok := param.(*deviceClass) - if !ok { - return statusInvalidParameter - } - // read current setup buffer from given deviceClass in param - var setup deviceSetup - setupStatus := setup.parse(class.setupBuffer) - if !setupStatus.OK() { - return setupStatus - } - - // read current device state of receiver - var state deviceStateID - s := d.status(deviceStatusDeviceState, &state) - if !s.OK() { - return statusInvalidHandle - } - - // allocate buffer for request responses - buffer := []uint8{} - length := uint32(0) - - if message.isSetup { - // verify message received contains expected setup data - if nil == message.buffer || deviceSetupSize != message.length { - return statusInvalidRequest - } - // read setup data from given message buffer - s = setup.parse(message.buffer) - if !s.OK() { - return statusInvalidRequest - } - // process message as a received setup request - if (setup.bmRequestType & specRequestTypeTypeMsk) == specRequestTypeTypeStandard { - // handle standard request - if int(setup.bRequest) <= specRequestStandardSynchFrame { - _ = d.requestStandard(&setup, &buffer, &length) - } - } else { - if 0 != setup.wLength && - (setup.bmRequestType&specRequestTypeDirMsk) == specRequestTypeDirOut { - if (setup.bmRequestType & specRequestTypeTypeClass) == specRequestTypeTypeClass { - req := deviceControlRequest{ - setup: setup, - buffer: nil, - length: uint32(setup.wLength), - isSetup: true, - } - d.classEvent(deviceClassEventClassRequest, &req) - buffer = req.buffer - length = req.length - } else if (setup.bmRequestType & specRequestTypeTypeVendor) == specRequestTypeTypeVendor { - req := deviceControlRequest{ - setup: setup, - buffer: nil, - length: uint32(setup.wLength), - isSetup: true, - } - d.event(deviceEventVendorRequest, &req) - buffer = req.buffer - length = req.length - } - if s.OK() { - return d.receive(specEndpointControl, buffer, uint32(setup.wLength)) - } - } else { - if (setup.bmRequestType & specRequestTypeTypeClass) == specRequestTypeTypeClass { - req := deviceControlRequest{ - setup: setup, - buffer: nil, - length: uint32(setup.wLength), - isSetup: true, - } - d.classEvent(deviceClassEventClassRequest, &req) - buffer = req.buffer - length = req.length - } else if (setup.bmRequestType & specRequestTypeTypeVendor) == specRequestTypeTypeVendor { - req := deviceControlRequest{ - setup: setup, - buffer: nil, - length: uint32(setup.wLength), - isSetup: true, - } - d.event(deviceEventVendorRequest, &req) - buffer = req.buffer - length = req.length - } - } - } - s = d.feedback(&setup, s, deviceControlPipeSetupStage, &buffer, &length) - } else if deviceStateAddressing == state { - // handle standard request - if int(setup.bRequest) <= specRequestStandardSynchFrame { - _ = d.requestStandard(&setup, &buffer, &length) - } - } else if 0 != message.length && 0 != setup.wLength && - (setup.bmRequestType&specRequestTypeDirMsk) == specRequestTypeDirOut { - if setup.bmRequestType&specRequestTypeTypeClass == specRequestTypeTypeClass { - req := deviceControlRequest{ - setup: setup, - buffer: message.buffer, - length: message.length, - isSetup: false, - } - d.classEvent(deviceClassEventClassRequest, &req) - } else if setup.bmRequestType&specRequestTypeTypeVendor == specRequestTypeTypeVendor { - req := deviceControlRequest{ - setup: setup, - buffer: message.buffer, - length: message.length, - isSetup: false, - } - d.event(deviceEventVendorRequest, &req) - } - s = d.feedback(&setup, s, deviceControlPipeDataStage, &buffer, &length) - } - - return s -} - -func (d *device) requestStandard( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - switch setup.bRequest { - case specRequestStandardGetStatus: - return d.requestGetStatus(setup, buffer, length) - case specRequestStandardClearFeature, specRequestStandardSetFeature: - return d.requestSetClearFeature(setup, buffer, length) - case specRequestStandardSetAddress: - return d.requestSetAddress(setup, buffer, length) - case specRequestStandardGetDescriptor: - return d.requestGetDescriptor(setup, buffer, length) - case specRequestStandardGetConfiguration: - return d.requestGetConfiguration(setup, buffer, length) - case specRequestStandardSetConfiguration: - return d.requestSetConfiguration(setup, buffer, length) - case specRequestStandardGetInterface: - return d.requestGetInterface(setup, buffer, length) - case specRequestStandardSetInterface: - return d.requestSetInterface(setup, buffer, length) - case specRequestStandardSynchFrame: - return d.requestSynchFrame(setup, buffer, length) - default: - return statusInvalidRequest - } -} - -func (d *device) requestGetStatus( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestSetClearFeature( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestSetAddress( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestGetDescriptor( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestGetConfiguration( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestSetConfiguration( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestGetInterface( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestSetInterface( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) requestSynchFrame( - setup *deviceSetup, buffer *[]uint8, length *uint32) status { - return statusSuccess -} - -func (d *device) classEvent(ev deviceClassEventID, param interface{}) { - if nil != d.class && nil != d.class.config { - // route the event to all class configurations - for i := range d.class.config { - _ = d.class.config[i].driver.event(ev, param) - } - } -} - -func (d *device) event(ev deviceEventID, param interface{}) { - - switch ev { - case deviceEventBusReset: - // initialize control pipes - d.initControlPipes() - - // notify all classes of a bus reset signal - for i := range d.class.config { - _ = d.class.config[i].driver.event(deviceClassEventDeviceReset, d.class) - } - } - // notify the application driver of all events - if nil != d.class.handler { - _ = d.class.handler.deviceEvent(ev, param) - } -} - -func (d *device) notify(message deviceNotification) { - - switch message.code { - case deviceNotifyBusReset: - d.notifyReset(message) - - default: - endpoint, direction := unpackEndpoint(uint8(message.code)) - - if endpoint < configDeviceMaxEndpoints { - if nil != d.endpointControl[(endpoint<<1)|direction].handler { - if message.isSetup { - d.endpointControl[0].isBusy = false - d.endpointControl[1].isBusy = false - } else { - d.endpointControl[(endpoint<<1)|direction].isBusy = false - } - // call endpoint callback - _ = d.endpointControl[(endpoint<<1)|direction].handler.controlEndpoint( - deviceEndpointControlMessage{ - buffer: message.buffer, - length: message.length, - isSetup: message.isSetup, - }, - d.endpointControl[(endpoint<<1)|direction].param, - ) - } - } - } -} - -func (d *device) notifyReset(message deviceNotification) { - - d.isResetting = true - _ = d.control(deviceControlSetDefaultStatus, nil) - - d.state = deviceStateDefault - d.deviceAddress = 0 - - for count := 0; count < 2*configDeviceMaxEndpoints; count++ { - d.endpointControl[count].handler = nil - d.endpointControl[count].param = nil - d.endpointControl[count].isBusy = false - } - - d.event(deviceEventBusReset, nil) - d.isResetting = false -} - -func (d *device) status(deviceStatus deviceStatusID, param interface{}) status { - - if nil == param { - return statusInvalidParameter - } - - switch deviceStatus { - case deviceStatusSpeed: - return d.control(deviceControlGetSpeed, param) - - case deviceStatusOTG: - return d.control(deviceControlGetOTGStatus, param) - - case deviceStatusDeviceState: - if state, ok := param.(*deviceStateID); ok { - *state = d.state - return statusSuccess - } - return statusInvalidParameter - - case deviceStatusAddress: - if address, ok := param.(*uint8); ok { - *address = d.deviceAddress - return statusSuccess - } - return statusInvalidParameter - - case deviceStatusDevice: - return d.control(deviceControlGetDeviceStatus, param) - - case deviceStatusEndpoint: - return d.control(deviceControlGetEndpointStatus, param) - - case deviceStatusSynchFrame: - return d.control(deviceControlGetSynchFrame, param) - - default: - return statusInvalidParameter - } -} - -func (d *device) setStatus(deviceStatus deviceStatusID, param interface{}) status { - - switch deviceStatus { - case deviceStatusOTG: - return d.control(deviceControlSetOTGStatus, param) - - case deviceStatusDeviceState: - if state, ok := param.(deviceStateID); ok { - d.state = state - return statusSuccess - } - return statusInvalidParameter - - case deviceStatusAddress: - if d.state != deviceStateAddressing { - if address, ok := param.(uint8); ok { - d.deviceAddress = address - d.state = deviceStateAddressing - return d.control(deviceControlPreSetDeviceAddress, d.deviceAddress) - } - return statusInvalidParameter - } - return d.control(deviceControlSetDeviceAddress, d.deviceAddress) - - case deviceStatusBusResume: - return d.control(deviceControlResume, param) - - case deviceStatusBusSleepResume: - return d.control(deviceControlSleepResume, param) - - case deviceStatusBusSuspend: - return d.control(deviceControlSuspend, param) - - case deviceStatusBusSleep: - return d.control(deviceControlSleep, param) - - default: - return statusInvalidParameter - } -} - -func (d *device) busSpeed(speed *uint8) status { - return d.status(deviceStatusSpeed, speed) -} - -func (d *device) setBusSpeed(speed uint8) status { - // TODO - return statusSuccess -} - -func (d *device) deviceDescriptor(desc *deviceGetDeviceDescriptor) status { - if int(d.port) < len(configDeviceCDCACMDescriptor) { - if nil != configDeviceCDCACMDescriptor[d.port].pDevice { - desc.buffer = *configDeviceCDCACMDescriptor[d.port].pDevice - desc.length = specDescriptorLengthDevice - return statusSuccess - } - } - return statusInvalidHandle -} - -func (d *device) configurationDescriptor(desc *deviceGetConfigurationDescriptor) status { - if int(d.port) < len(configDeviceCDCACMDescriptor) { - if nil != configDeviceCDCACMDescriptor[d.port].pConfig { - desc.buffer = *configDeviceCDCACMDescriptor[d.port].pConfig - desc.length = uint32(descriptorConfigurationCDCACMSize) - return statusSuccess - } - } - return statusInvalidHandle -} - -func (d *device) stringDescriptor(desc *deviceGetStringDescriptor) status { - if 0 == desc.stringIndex { - desc.buffer = descriptorStringCDCACMLanguage - desc.length = uint32(len(descriptorStringCDCACMLanguage)) - return statusSuccess - } - if int(d.port) < len(configDeviceCDCACMDescriptor) { - for _, lang := range configDeviceCDCACMDescriptor[d.port].language { - if desc.languageID == lang.ident { - if int(desc.stringIndex) < len(lang.pString) { - desc.buffer = *lang.pString[desc.stringIndex] - desc.length = uint32(len(desc.buffer)) - } - } - } - } - return statusInvalidRequest -} - -func (s deviceSetup) pack() deviceSetupBitmap { - return deviceSetupBitmap( - ((uint64(s.bmRequestType) & 0xFF) << 0) | // uint8 // 8 (bits) - ((uint64(s.bRequest) & 0xFF) << 8) | // uint8 // 8 - ((uint64(s.wValue) & 0xFFFF) << 16) | // uint16 // 16 - ((uint64(s.wIndex) & 0xFFFF) << 32) | // uint16 // 16 - ((uint64(s.wLength) & 0xFFFF) << 48)) // uint16 // 16 (= 64 bits) -} - -func (s deviceSetup) bytes() deviceSetupBuffer { - return [deviceSetupSize]uint8{ - s.bmRequestType, - s.bRequest, - // for 16-bit words: low-byte is at index N, high-byte is at N+1 - uint8(s.wValue), uint8(s.wValue >> 8), - uint8(s.wIndex), uint8(s.wIndex >> 8), - uint8(s.wLength), uint8(s.wLength >> 8), - } -} - -func (s deviceSetupBitmap) bytes() deviceSetupBuffer { - return [deviceSetupSize]uint8{ - uint8(s >> 0), uint8(s >> 8), uint8(s >> 16), uint8(s >> 24), - uint8(s >> 32), uint8(s >> 40), uint8(s >> 48), uint8(s >> 56), - } -} - -func (s *deviceSetup) parse(buffer []uint8) status { - if nil == buffer || len(buffer) < deviceSetupSize { - return statusInvalidParameter - } - s.bmRequestType = buffer[0] - s.bRequest = buffer[1] - s.wValue = (uint16(buffer[3]) << 8) | uint16(buffer[2]) - s.wIndex = (uint16(buffer[5]) << 8) | uint16(buffer[4]) - s.wLength = (uint16(buffer[7]) << 8) | uint16(buffer[6]) - return statusSuccess -} diff --git a/src/machine/usb/device_cdc.go b/src/machine/usb/device_cdc.go deleted file mode 100644 index fadec6193..000000000 --- a/src/machine/usb/device_cdc.go +++ /dev/null @@ -1,135 +0,0 @@ -package usb - -const ( - // Communication Class - deviceCDCCommClass = 0x02 - // Data Class - deviceCDCDataClass = 0x0A - - // Communication Class SubClass Codes - deviceCDCDirectLineControlModel = 0x01 - deviceCDCAbstractControlModel = 0x02 - deviceCDCTelephoneControlModel = 0x03 - deviceCDCMultiChannelControlModel = 0x04 - deviceCDCCAPIControlMopdel = 0x05 - deviceCDCEthernetNetworkingControlModel = 0x06 - deviceCDCATMNetworkingControlModel = 0x07 - deviceCDCWirelessHandsetControlModel = 0x08 - deviceCDCDeviceManagement = 0x09 - deviceCDCMobileDirectLineModel = 0x0A - deviceCDCOBEX = 0x0B - deviceCDCEthernetEmulationModel = 0x0C - - // Communication Class Protocol Codes - deviceCDCNoClassSpecificProtocol = 0x00 // also for Data Class Protocol Code - deviceCDCAT250Protocol = 0x01 - deviceCDCATPCCA101Protocol = 0x02 - deviceCDCATPCCA101AnnexO = 0x03 - deviceCDCATGSM707 = 0x04 - deviceCDCAT3GPP27007 = 0x05 - deviceCDCATTIACDMA = 0x06 - deviceCDCEthernetEmulationProtocol = 0x07 - deviceCDCExternalProtocol = 0xFE - deviceCDCVendorSpecific = 0xFF // also for Data Class Protocol Code - - // Data Class Protocol Codes - deviceCDCPyhsicalInterfaceProtocol = 0x30 - deviceCDCHDLCProtocol = 0x31 - deviceCDCTransparentProtocol = 0x32 - deviceCDCManagementProtocol = 0x50 - deviceCDCDataLinkQ931Protocol = 0x51 - deviceCDCDataLinkQ921Protocol = 0x52 - deviceCDCDataCompressionV42BIS = 0x90 - deviceCDCEuroISDNProtocol = 0x91 - deviceCDCRateAdaptionISDNV24 = 0x92 - deviceCDCCAPICommands = 0x93 - deviceCDCHostBasedDriver = 0xFD - deviceCDCUnitFunctional = 0xFE - - // Descriptor SubType in Communications Class Functional Descriptors - deviceCDCHeaderFuncDesc = 0x00 - deviceCDCCallManagementFuncDesc = 0x01 - deviceCDCAbstractControlFuncDesc = 0x02 - deviceCDCDirectLineFuncDesc = 0x03 - deviceCDCTelephoneRingerFuncDesc = 0x04 - deviceCDCTelephoneReportFuncDesc = 0x05 - deviceCDCUnionFuncDesc = 0x06 - deviceCDCCountrySelectFuncDesc = 0x07 - deviceCDCTelephoneModesFuncDesc = 0x08 - deviceCDCTerminalFuncDesc = 0x09 - deviceCDCNetworkChannelFuncDesc = 0x0A - deviceCDCProtocolUnitFuncDesc = 0x0B - deviceCDCExtensionUnitFuncDesc = 0x0C - deviceCDCMultiChannelFuncDesc = 0x0D - deviceCDCCAPIControlFuncDesc = 0x0E - deviceCDCEthernetNetworkingFuncDesc = 0x0F - deviceCDCATMNetworkingFuncDesc = 0x10 - deviceCDCWirelessControlFuncDesc = 0x11 - deviceCDCMobileDirectLineFuncDesc = 0x12 - deviceCDCMDLMDetailFuncDesc = 0x13 - deviceCDCDeviceManagementFuncDesc = 0x14 - deviceCDCOBEXFuncDesc = 0x15 - deviceCDCCommandSetFuncDesc = 0x16 - deviceCDCCommandSetDetailFuncDesc = 0x17 - deviceCDCTelephoneControlFuncDesc = 0x18 - deviceCDCOBEXServiceIDFuncDesc = 0x19 - - deviceCDCRequestSendEncapsulatedCommand = 0x00 // CDC request SEND_ENCAPSULATED_COMMAND - deviceCDCRequestGetEncapsulatedResponse = 0x01 // CDC request GET_ENCAPSULATED_RESPONSE - deviceCDCRequestSetCommFeature = 0x02 // CDC request SET_COMM_FEATURE - deviceCDCRequestGetCommFeature = 0x03 // CDC request GET_COMM_FEATURE - deviceCDCRequestClearCommFeature = 0x04 // CDC request CLEAR_COMM_FEATURE - deviceCDCRequestSetAuxLineState = 0x10 // CDC request SET_AUX_LINE_STATE - deviceCDCRequestSetHookState = 0x11 // CDC request SET_HOOK_STATE - deviceCDCRequestPulseSetup = 0x12 // CDC request PULSE_SETUP - deviceCDCRequestSendPulse = 0x13 // CDC request SEND_PULSE - deviceCDCRequestSetPulseTime = 0x14 // CDC request SET_PULSE_TIME - deviceCDCRequestRingAuxJack = 0x15 // CDC request RING_AUX_JACK - deviceCDCRequestSetLineCoding = 0x20 // CDC request SET_LINE_CODING - deviceCDCRequestGetLineCoding = 0x21 // CDC request GET_LINE_CODING - deviceCDCRequestSetControlLineState = 0x22 // CDC request SET_CONTROL_LINE_STATE - deviceCDCRequestSendBreak = 0x23 // CDC request SEND_BREAK - deviceCDCRequestSetRingerParams = 0x30 // CDC request SET_RINGER_PARAMS - deviceCDCRequestGetRingerParams = 0x31 // CDC request GET_RINGER_PARAMS - deviceCDCRequestSetOperationParam = 0x32 // CDC request SET_OPERATION_PARAM - deviceCDCRequestGetOperationParam = 0x33 // CDC request GET_OPERATION_PARAM - deviceCDCRequestSetLineParams = 0x34 // CDC request SET_LINE_PARAMS - deviceCDCRequestGetLineParams = 0x35 // CDC request GET_LINE_PARAMS - deviceCDCRequestDialDigits = 0x36 // CDC request DIAL_DIGITS - deviceCDCRequestSetUnitParameter = 0x37 // CDC request SET_UNIT_PARAMETER - deviceCDCRequestGetUnitParameter = 0x38 // CDC request GET_UNIT_PARAMETER - deviceCDCRequestClearUnitParameter = 0x39 // CDC request CLEAR_UNIT_PARAMETER - deviceCDCRequestSetEthernetMulticastFilters = 0x40 // CDC request SET_ETHERNET_MULTICAST_FILTERS - deviceCDCRequestSetEthernetPowPatternFilter = 0x41 // CDC request SET_ETHERNET_POW_PATTER_FILTER - deviceCDCRequestGetEthernetPowPatternFilter = 0x42 // CDC request GET_ETHERNET_POW_PATTER_FILTER - deviceCDCRequestSetEthernetPacketFilter = 0x43 // CDC request SET_ETHERNET_PACKET_FILTER - deviceCDCRequestGetEthernetStatistic = 0x44 // CDC request GET_ETHERNET_STATISTIC - deviceCDCRequestSetATMDataFormat = 0x50 // CDC request SET_ATM_DATA_FORMAT - deviceCDCRequestGetATMDeviceStatistics = 0x51 // CDC request GET_ATM_DEVICE_STATISTICS - deviceCDCRequestSetATMDefaultVC = 0x52 // CDC request SET_ATM_DEFAULT_VC - deviceCDCRequestGetATMVCStatistics = 0x53 // CDC request GET_ATM_VC_STATISTICS - deviceCDCRequestMDLMSpecificRequestsMask = 0x7F // CDC request MDLM_SPECIFIC_REQUESTS_MASK - - deviceCDCNotifyNetworkConnection = 0x00 // CDC notify NETWORK_CONNECTION - deviceCDCNotifyResponseAvail = 0x01 // CDC notify RESPONSE_AVAIL - deviceCDCNotifyAuxJackHookState = 0x08 // CDC notify AUX_JACK_HOOK_STATE - deviceCDCNotifyRingDetect = 0x09 // CDC notify RING_DETECT - deviceCDCNotifySerialState = 0x20 // CDC notify SERIAL_STATE - deviceCDCNotifyCallStateChange = 0x28 // CDC notify CALL_STATE_CHANGE - deviceCDCNotifyLineStateChange = 0x29 // CDC notify LINE_STATE_CHANGE - deviceCDCNotifyConnectionSpeedChange = 0x2A // CDC notify CONNECTION_SPEED_CHANGE - - deviceCDCFeatureAbstractState = 0x01 // CDC feature select ABSTRACT_STATE - deviceCDCFeatureCountrySetting = 0x02 // CDC feature select COUNTRY_SETTING - - deviceCDCControlSigBitmapCarrierActivation = 0x02 // CDC control signal CARRIER_ACTIVATION - deviceCDCControlSigBitmapDTEPresence = 0x01 // CDC control signal DTE_PRESENCE - deviceCDCUARTStateRxCarrier = 0x01 // UART state RX_CARRIER - deviceCDCUARTStateTxCarrier = 0x02 // UART state TX_CARRIER - deviceCDCUARTStateBreak = 0x04 // UART state BREAK - deviceCDCUARTStateRingSignal = 0x08 // UART state RING_SIGNAL - deviceCDCUARTStateFraming = 0x10 // UART state FRAMING - deviceCDCUARTStateParity = 0x20 // UART state PARITY - deviceCDCUARTStateOverrun = 0x40 // UART state OVERRUN - -) diff --git a/src/machine/usb/device_cdc_acm.go b/src/machine/usb/device_cdc_acm.go deleted file mode 100644 index 0b0052e1c..000000000 --- a/src/machine/usb/device_cdc_acm.go +++ /dev/null @@ -1,690 +0,0 @@ -package usb - -import "bytes" - -type ( - deviceCDCACMEventID uint8 - - // deviceCDCACMConfig defines the platform-specific configuration settings for - // a single CDC-ACM device class on a given USB port. - // - // To connect the USB CDC-ACM device driver to a particular platform, there - // should be one instance for each USB CDC-ACM port, defined in global array - // configDeviceCDCACM, indexed by USB port. - deviceCDCACMConfig struct { - // USB configuration - interfaceSpeed uint8 // Low/Full/High-speed - // CDC-ACM Serial line configuration - lineCodingSize uint32 // Size of line-coding message - lineCodingBaudRate uint32 // Data terminal rate - lineCodingCharFormat uint32 // Character format - lineCodingParityType uint32 // Parity type - lineCodingDataBits uint32 // Data word size - // CDC-ACM Communication/control interface - commInterfaceIndex uint8 // Communication/control interface index - commInterruptInEndpoint uint8 // Interrupt input endpoint index (address) - commInterruptInPacketSize uint16 // Interrupt input packet size - commInterruptInInterval uint8 // Interrupt input interval - // CDC-ACM Data interface - dataInterfaceIndex uint8 // Data interface index - dataBulkInEndpoint uint8 // Bulk input endpoint index (address) - dataBulkInPacketSize uint16 // Bulk input packet size - dataBulkOutEndpoint uint8 // Bulk output endpoint index (address) - dataBulkOutPacketSize uint16 // Bulk output packet size - } - - deviceCDCACM struct { - device *device // The handle of the USB device. - config *deviceClassConfig // The class configure structure. - info deviceCDCACMInfo // The ACM serial state. - comm *deviceInterface // The CDC communication interface handle. - data *deviceInterface // The CDC data interface handle. - sendBuffer *deviceCDCACMDataBuffer // Pointer to the global send buffer - recvBuffer *deviceCDCACMDataBuffer // Pointer to the global receive buffer - bulkIn deviceCDCACMPipe // The bulk in pipe for sending packet to host. - bulkOut deviceCDCACMPipe // The bulk out pipe for receiving packet from host. - interruptIn deviceCDCACMPipe // The interrupt in pipe for notifying the device state to host. - interfaceNumber uint8 // The current interface number. - alternate uint8 // The alternate setting value of the interface. - hasSentState bool // The device has primed the state in interrupt pipe - speed uint8 // Speed of USB device (Full/Low/High) - lineCodingSize uint32 // Size of line-coding message - baudRate uint32 // Data terminal rate - charFormat uint32 // Character format - parityType uint32 // Parity type - dataBits uint32 // Data word size - sendSize uint32 // Number of bytes scheduled in global send buffer - recvSize uint32 // Number of bytes scheduled in global receive buffer - } - - deviceCDCACMDataBuffer [configDeviceBufferSize]uint8 - deviceCDCACMAlternateList [configDeviceCDCACMInterfaceCount]uint16 - deviceCDCACMSerialState [deviceCDCACMSerialStateSize]uint8 - - deviceCDCACMRequestParam struct { - buffer *[]uint8 // The pointer to the address of the buffer for CDC class request. - length *uint32 // The pointer to the length of the buffer for CDC class request. - interfaceIndex uint16 // The interface index of the setup packet. - setupValue uint16 // The wValue field of the setup packet. - isSetup bool // The flag indicates if it is a setup packet - } - - deviceCDCACMPipe struct { - pipeDataBuffer []uint8 // pipe data buffer backup when stall - pipeDataLen uint32 // pipe data length backup when stall - pipeStall bool // pipe is stall - ep uint8 // The endpoint number of the pipe. - isBusy bool // The pipe is transferring packet - } - - deviceCDCACMInfo struct { - serialState deviceCDCACMSerialState // Serial state buffer of the CDC device to notify the serial state to host. - dtePresent bool // A flag to indicate whether DTE is present. - breakDuration uint16 // Length of time in milliseconds of the break signal - dteStatus uint8 // Status of data terminal equipment - currentInterface uint8 // Current interface index. - uartState uint16 // UART state of the CDC device. - } -) - -const ( - deviceCDCACMEventSendResponse deviceCDCACMEventID = iota + 1 // This event indicates the bulk send transfer is complete or cancelled etc. - deviceCDCACMEventRecvResponse // This event indicates the bulk receive transfer is complete or cancelled etc.. - deviceCDCACMEventSerialStateNotify // This event indicates the serial state has been sent to the host. - deviceCDCACMEventSendEncapsulatedCommand // This event indicates the device received the SEND_ENCAPSULATED_COMMAND request. - deviceCDCACMEventGetEncapsulatedResponse // This event indicates the device received the GET_ENCAPSULATED_RESPONSE request. - deviceCDCACMEventSetCommFeature // This event indicates the device received the SET_COMM_FEATURE request. - deviceCDCACMEventGetCommFeature // This event indicates the device received the GET_COMM_FEATURE request. - deviceCDCACMEventClearCommFeature // This event indicates the device received the CLEAR_COMM_FEATURE request. - deviceCDCACMEventGetLineCoding // This event indicates the device received the GET_LINE_CODING request. - deviceCDCACMEventSetLineCoding // This event indicates the device received the SET_LINE_CODING request. - deviceCDCACMEventSetControlLineState // This event indicates the device received the SET_CONTRL_LINE_STATE request. - deviceCDCACMEventSendBreak // This event indicates the device received the SEND_BREAK request. - - deviceCDCACMRequestNotify = 0xA1 - - deviceCDCACMInfoNotifyPacketSize = 8 // (bytes) - deviceCDCACMInfoUARTBitmapSize = 2 // - deviceCDCACMSerialStateSize = deviceCDCACMInfoNotifyPacketSize + deviceCDCACMInfoUARTBitmapSize -) - -var ( - deviceCDCACMDataSendBuffer = [configDeviceCDCACMCount]deviceCDCACMDataBuffer{} - deviceCDCACMDataRecvBuffer = [configDeviceCDCACMCount]deviceCDCACMDataBuffer{} - - deviceCDCACMLineCoding = [configDeviceCDCACMCount][][]uint8{ - { // USB CDC-ACM port 0 - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // configuration index 1 - }, - } - - deviceCDCACMConfigInstance = [configDeviceCDCACMCount][]deviceClassConfig{ - {{ - driver: &deviceCDCACM{}, - info: deviceClassInfo{ - classID: deviceClassCDC, - interfaceList: []deviceClassInterface{ - { // USB CDC-ACM communications/control interface - classCode: deviceCDCCommClass, - subclassCode: deviceCDCAbstractControlModel, - protocolCode: deviceCDCNoClassSpecificProtocol, - deviceInterface: []deviceInterface{{ - alternateSetting: 0, - endpoint: []deviceEndpoint{ - {transferType: specEndpointInterrupt}, - }, - }}, - }, - { // USB CDC-ACM serial data interface - classCode: deviceCDCDataClass, - subclassCode: 0x00, - protocolCode: deviceCDCNoClassSpecificProtocol, - deviceInterface: []deviceInterface{{ - alternateSetting: 0, - endpoint: []deviceEndpoint{ - {transferType: specEndpointBulk}, - {transferType: specEndpointBulk}, - }, - }}, - }, - }, - }, - }}, - } - - deviceCDCACMBufferInvalid32 = leU32(0xFFFFFFFF) -) - -func (acm *deviceCDCACM) init(device *device, config *deviceClassConfig, id uint8) status { - - // initialize our associated object references - acm.device = device - acm.config = config - - // grab references to the global data buffers - acm.sendBuffer = &deviceCDCACMDataSendBuffer[device.port] - acm.recvBuffer = &deviceCDCACMDataRecvBuffer[device.port] - - // initialize line-coding details from global configuration - acm.speed = configDeviceCDCACM[device.port][id-1].interfaceSpeed - acm.lineCodingSize = configDeviceCDCACM[device.port][id-1].lineCodingSize - acm.baudRate = configDeviceCDCACM[device.port][id-1].lineCodingBaudRate - acm.charFormat = configDeviceCDCACM[device.port][id-1].lineCodingCharFormat - acm.parityType = configDeviceCDCACM[device.port][id-1].lineCodingParityType - acm.dataBits = configDeviceCDCACM[device.port][id-1].lineCodingDataBits - - lineCoding := deviceCDCACMLineCoding[device.port][id-1] - lineCoding[0] = uint8(acm.baudRate >> 0) - lineCoding[1] = uint8(acm.baudRate >> 8) - lineCoding[2] = uint8(acm.baudRate >> 16) - lineCoding[3] = uint8(acm.baudRate >> 24) - lineCoding[4] = uint8(acm.charFormat) - lineCoding[5] = uint8(acm.parityType) - lineCoding[6] = uint8(acm.dataBits) - - // initialize remaining state data - acm.alternate = 0xFF - - return statusSuccess -} - -func (acm *deviceCDCACM) deinit() status { - return statusSuccess -} - -func (acm *deviceCDCACM) initEndpoints() status { - - // find the communication/control interface in our CDC-ACM configuration list - acm.interfaceNumber, acm.comm = acm.findInterface(deviceCDCCommClass) - - // verify we found a valid communication/control interface - if nil == acm.comm { - return statusInvalidHandle - } - - // initialize all of the communication/control input endpoints - if s := acm.initInterfaceEndpoints(specIn, specEndpointInterrupt); !s.OK() { - return s - } - - // find the data interface in our CDC-ACM configuration list - _, acm.data = acm.findInterface(deviceCDCDataClass) - - // verify we found a valid data interface - if nil == acm.data { - return statusInvalidHandle - } - - // initialize all of the data input endpoints - if s := acm.initInterfaceEndpoints(specIn, specEndpointBulk); !s.OK() { - return s - } - // initialize all of the data output endpoints - if s := acm.initInterfaceEndpoints(specOut, specEndpointBulk); !s.OK() { - return s - } - - return statusSuccess -} - -func (acm *deviceCDCACM) initInterfaceEndpoints(direction, transferType uint8) status { - - // select the relevant fields and callbacks for our given interface type - pipe, deviceInterface := acm.endpointInterface(direction, transferType) - if nil == deviceInterface { - return statusInvalidParameter - } - - // initialize each endpoint with given direction and transfer type - for _, ep := range deviceInterface.endpoint { - num, dir := unpackEndpoint(ep.address) - if dir == direction && ep.transferType == transferType { - pipe.pipeDataBuffer = deviceCDCACMBufferInvalid32 - pipe.pipeDataLen = 0 - pipe.pipeStall = false - pipe.ep = num - pipe.isBusy = false - - if s := acm.device.initEndpoint(&deviceEndpointConfig{ - maxPacketSize: ep.maxPacketSize, - address: ep.address, - transferType: ep.transferType, - zlt: 0, - interval: ep.interval, - }, acm, pipe); !s.OK() { - return s - } - } - } - - return statusSuccess -} - -func (acm *deviceCDCACM) deinitEndpoints() status { - - if nil == acm.device { - return statusInvalidHandle - } - - if nil != acm.comm { - for i := range acm.comm.endpoint { - _ = acm.device.deinitEndpoint(acm.comm.endpoint[i].address) - } - acm.comm = nil - } - if nil != acm.data { - for i := range acm.data.endpoint { - _ = acm.device.deinitEndpoint(acm.data.endpoint[i].address) - } - acm.data = nil - } - - return statusSuccess -} - -func (acm *deviceCDCACM) event(event deviceClassEventID, param interface{}) (s status) { - - // assume success unless error condition deliberately detected - s = statusSuccess - - switch event { - case deviceClassEventDeviceReset: - // bus reset, clear the selected configuration - acm.config = nil - - case deviceClassEventSetConfiguration: - if id, ok := param.(uint8); ok { - // configuration index is 1-based, meaning configuration 0 is invalid - if 0 == id || int(id) > len(acm.device.class.config) { - return statusInvalidParameter - } - if &acm.device.class.config[id-1] == acm.config { - break // configuration already selected - } - // de-initialize endpoints of current configuration - if s = acm.deinitEndpoints(); !s.OK() { - break - } - // select new configuration, reset alternate setting - acm.config = &acm.device.class.config[id-1] - acm.alternate = 0 - // initialize endpoints of new configuration - if s = acm.initEndpoints(); !s.OK() { - break - } - } else { - // unexpected parameter, should be uint8 (configuration index) - s = statusInvalidParameter - } - - case deviceClassEventSetInterface: - if interfaceAlternate, ok := param.(uint16); ok { - alternate := uint8(interfaceAlternate & 0xFF) - if acm.interfaceNumber != uint8(interfaceAlternate>>8) { - break // requested alternate from interface different than current - } - if alternate == acm.alternate { - break // requested alternate same as current - } - // de-initialize endpoints of current configuration - if s = acm.deinitEndpoints(); !s.OK() { - break - } - // select new alternate - acm.alternate = alternate - // initialize endpoints of new configuration - if s = acm.initEndpoints(); !s.OK() { - break - } - } else { - // unexpected parameter, should be uint16: interface (hi), alternate (lo) - s = statusInvalidParameter - } - - case deviceClassEventSetEndpointHalt: - // verify parameter and fields - if address, ok := param.(uint8); ok { - if nil != acm.config && nil != acm.comm && nil != acm.data { - // check if given endpoint is a communication/control endpoint - for _, e := range acm.comm.endpoint { - if address == e.address { - // found endpoint, set stall flag - acm.interruptIn.pipeStall = true - // notify device - c := acm.device.control(deviceControlEndpointStall, address) - if s.OK() && !c.OK() { - s = c - } - } - } - // check if given endpoint is a data endpoint - for _, e := range acm.data.endpoint { - if address == e.address { - _, direction := unpackEndpoint(address) - // found endpoint, set stall flag - if specIn == direction { - acm.bulkIn.pipeStall = true - } else { - acm.bulkOut.pipeStall = true - } - // notify device - c := acm.device.control(deviceControlEndpointStall, address) - if s.OK() && !c.OK() { - s = c - } - } - } - } else { - s = statusInvalidHandle - } - } else { - // unexpected parameter, should be uint8 (endpoint address) - s = statusInvalidParameter - } - - case deviceClassEventClearEndpointHalt: - // verify parameter and fields - if address, ok := param.(uint8); ok { - if nil != acm.config && nil != acm.comm && nil != acm.data { - // check if given endpoint is a communication/control endpoint - for _, e := range acm.comm.endpoint { - if address == e.address { - // found endpoint, notify device - c := acm.device.control(deviceControlEndpointUnstall, address) - if s.OK() && !c.OK() { - s = c - } - _, direction := unpackEndpoint(address) - if specIn == direction { - // flush any buffered data written to the stalled endpoint - if acm.interruptIn.pipeStall { - // clear stall flag - acm.interruptIn.pipeStall = false - // verify the buffer has valid data - if !bytes.Equal(acm.interruptIn.pipeDataBuffer, deviceCDCACMBufferInvalid32) { - // transmit - u := acm.device.send( - acm.interruptIn.ep, - acm.interruptIn.pipeDataBuffer, - acm.interruptIn.pipeDataLen) - if !u.OK() { - // notify upper layer driver of communication/control event - _ = acm.controlEndpoint( - deviceEndpointControlMessage{ - buffer: acm.interruptIn.pipeDataBuffer, - length: acm.interruptIn.pipeDataLen, - isSetup: false, - }, - &acm.interruptIn, - ) - if s.OK() { - s = u - } - } - // clear the stalled endpoint buffer - acm.interruptIn.pipeDataBuffer = deviceCDCACMBufferInvalid32 - acm.interruptIn.pipeDataLen = 0 - } - } - } - } - } - // check if given endpoint is a data endpoint - for _, e := range acm.data.endpoint { - if address == e.address { - // found endpoint, notify device - c := acm.device.control(deviceControlEndpointUnstall, address) - if s.OK() && !c.OK() { - s = c - } - // check if endpoint is an input or output - _, direction := unpackEndpoint(address) - if specIn == direction { - // flush any buffered data written to the stalled endpoint - if acm.bulkIn.pipeStall { - // clear stall flag - acm.bulkIn.pipeStall = false - // verify the buffer has valid data - if !bytes.Equal(acm.bulkIn.pipeDataBuffer, deviceCDCACMBufferInvalid32) { - // transmit - u := acm.device.send( - acm.bulkIn.ep, - acm.bulkIn.pipeDataBuffer, - acm.bulkIn.pipeDataLen) - if !u.OK() { - // notify upper layer driver of data input event - _ = acm.controlEndpoint( - deviceEndpointControlMessage{ - buffer: acm.bulkIn.pipeDataBuffer, - length: acm.bulkIn.pipeDataLen, - isSetup: false, - }, - &acm.bulkIn, - ) - if s.OK() { - s = u - } - } - // clear the stalled endpoint buffer - acm.bulkIn.pipeDataBuffer = deviceCDCACMBufferInvalid32 - acm.bulkIn.pipeDataLen = 0 - } - } - } else { - // flush any buffered data read from the stalled endpoint - if acm.bulkOut.pipeStall { - // clear stall flag - acm.bulkOut.pipeStall = false - // verify the buffer has valid data - if !bytes.Equal(acm.bulkOut.pipeDataBuffer, deviceCDCACMBufferInvalid32) { - // receive - u := acm.device.receive( - acm.bulkOut.ep, - acm.bulkOut.pipeDataBuffer, - acm.bulkOut.pipeDataLen) - if !u.OK() { - // notify upper layer driver of data output event - _ = acm.controlEndpoint( - deviceEndpointControlMessage{ - buffer: acm.bulkOut.pipeDataBuffer, - length: acm.bulkOut.pipeDataLen, - isSetup: false, - }, - &acm.bulkOut, - ) - if s.OK() { - s = u - } - } - // clear the stalled endpoint buffer - acm.bulkOut.pipeDataBuffer = deviceCDCACMBufferInvalid32 - acm.bulkOut.pipeDataLen = 0 - } - } - } - } - } - } else { - s = statusInvalidHandle - } - } else { - // unexpected parameter, should be uint8 (endpoint address) - s = statusInvalidParameter - } - case deviceClassEventClassRequest: - // verify parameter and fields - if request, ok := param.(*deviceControlRequest); ok { - // verify requested interface is receiver's interface and request is CDC - if (request.setup.wIndex&0xFF) != uint16(acm.interfaceNumber) || - (request.setup.bmRequestType&specRequestTypeTypeMsk) != specRequestTypeTypeClass { - // construct standard parameter to be passed on to upper layer drivevr - param := deviceCDCACMRequestParam{ - buffer: &request.buffer, - length: &request.length, - interfaceIndex: request.setup.wIndex, - setupValue: request.setup.wValue, - isSetup: request.isSetup, - } - // translate request code to event code - var event deviceCDCACMEventID - switch request.setup.bRequest { - case deviceCDCRequestSendEncapsulatedCommand: - event = deviceCDCACMEventSendEncapsulatedCommand - case deviceCDCRequestGetEncapsulatedResponse: - event = deviceCDCACMEventGetEncapsulatedResponse - case deviceCDCRequestSetCommFeature: - event = deviceCDCACMEventSetCommFeature - case deviceCDCRequestGetCommFeature: - event = deviceCDCACMEventGetCommFeature - case deviceCDCRequestClearCommFeature: - event = deviceCDCACMEventClearCommFeature - case deviceCDCRequestGetLineCoding: - event = deviceCDCACMEventGetLineCoding - case deviceCDCRequestSetLineCoding: - event = deviceCDCACMEventSetLineCoding - case deviceCDCRequestSetControlLineState: - event = deviceCDCACMEventSetControlLineState - case deviceCDCRequestSendBreak: - event = deviceCDCACMEventSendBreak - default: - s = statusInvalidRequest - } - // notify request to upper layer driver - if nil != acm.device && nil != acm.device.class && - nil != acm.device.class.handler { - acm.device.class.handler.classEvent(uint32(event), param) - } - } else { - s = statusInvalidRequest - } - } else { - s = statusInvalidParameter - } - } - - return s -} - -func (acm *deviceCDCACM) send(ep uint8, buffer []uint8, length uint32) status { - var pipe *deviceCDCACMPipe - // select which endpoint pipe to write into - switch ep { - case acm.interruptIn.ep: - pipe = &acm.interruptIn - case acm.bulkIn.ep: - pipe = &acm.bulkIn - default: - return statusInvalidParameter - } - if pipe.isBusy { - return statusBusy - } - // set pipe busy flag - pipe.isBusy = true - // check if pipe stall flag is set - if pipe.pipeStall { - // write data to pipe buffer - pipe.pipeDataBuffer = buffer - pipe.pipeDataLen = length - return statusSuccess - } - // pass data to device for transmission - if s := acm.device.send(ep, buffer, length); !s.OK() { - pipe.isBusy = false - return s - } - return statusSuccess -} - -func (acm *deviceCDCACM) receive(ep uint8, buffer []uint8, length uint32) status { - var pipe *deviceCDCACMPipe - // select which endpoint pipe to read from - switch ep { - case acm.bulkOut.ep: - pipe = &acm.bulkOut - default: - return statusInvalidParameter - } - if pipe.isBusy { - return statusBusy - } - // set pipe busy flag - pipe.isBusy = true - // check if pipe stall flag is set - if pipe.pipeStall { - // write data to pipe buffer - pipe.pipeDataBuffer = buffer - pipe.pipeDataLen = length - return statusSuccess - } - // pass data to device for reception - if s := acm.device.receive(ep, buffer, length); !s.OK() { - pipe.isBusy = false - return s - } - return statusSuccess -} - -// findInterface returns the interface number and deviceInterface from the -// receiver's CDC-ACM configuration list whose classCode and alternateSetting -// equals the given classCode and receiver's current alternateSetting; -// otherwise, no such interface is found, returns 0 and nil. -func (acm *deviceCDCACM) findInterface(classCode uint8) (uint8, *deviceInterface) { - if nil == acm.device || nil == acm.config { - return 0, nil - } - for c := range acm.config.info.interfaceList { - dci := &acm.config.info.interfaceList[c] - if classCode == dci.classCode { - for d := range dci.deviceInterface { - if acm.alternate == dci.deviceInterface[d].alternateSetting { - return dci.interfaceNumber, &dci.deviceInterface[d] - } - } - } - } - return 0, nil -} - -func (acm *deviceCDCACM) endpointInterface( - direction, transferType uint8) (*deviceCDCACMPipe, *deviceInterface) { - - switch transferType { - case specEndpointInterrupt: - switch direction { - case specIn: - return &acm.interruptIn, acm.comm - } - case specEndpointBulk: - switch direction { - case specIn: - return &acm.bulkIn, acm.data - case specOut: - return &acm.bulkOut, acm.data - } - } - return nil, nil -} - -func (acm *deviceCDCACM) controlEndpoint( - message deviceEndpointControlMessage, param interface{}) status { - - if pipe, ok := param.(*deviceCDCACMPipe); ok { - var event deviceCDCACMEventID - switch pipe { - case &acm.interruptIn: - event = deviceCDCACMEventSerialStateNotify - case &acm.bulkIn: - event = deviceCDCACMEventSendResponse - case &acm.bulkOut: - event = deviceCDCACMEventRecvResponse - } - pipe.isBusy = false - if nil != acm.device && nil != acm.device.class && - nil != acm.device.class.handler { - acm.device.class.handler.classEvent(uint32(event), message) - return statusSuccess - } - } - return statusInvalidParameter -} diff --git a/src/machine/usb/device_controller.go b/src/machine/usb/device_controller.go deleted file mode 100644 index bf30719c2..000000000 --- a/src/machine/usb/device_controller.go +++ /dev/null @@ -1,288 +0,0 @@ -package usb - -import "unsafe" - -// deviceController provides hardware abstraction over a platform's physical -// USB device port controller (e.g., an EHCI-compliant peripheral). -// -// To connect the USB 2.0 device driver stack to a particular platform, the -// following method must be implemented: -// -// func (d *device) initController() deviceController -// -// This method shall return an implementation of deviceController, or nil if a -// controller cannot be allocated for the given port. -type ( - deviceController interface { - init() status // Controller initialization - deinit() status // Controller de-initialization - enable(enable bool) status // Controller enable runtime - interrupt() // Controller interrupt handler - process() status // Controller process interrupts - send(address uint8, buffer []uint8, length uint32) status // Controller send data - receive(address uint8, buffer []uint8, length uint32) status // Controller receive data - cancel(address uint8) status // Controller cancel transfer - control(command deviceControlID, param interface{}) status // Controller device control - critical(enter bool) status // Controller critical section - } - - // deviceControllerInterruptQueue represents a fixed-length, circular queue - // (FIFO) of interrupts. - // - // The enqueue and dequeue operations (methods enq and deq, respectively) are - // NOT interrupt-/thread-safe. The user must protect against race conditions - // using appropriate resources for their system. For example, the interface - // method (deviceController).critical(bool) implements the concept of critical - // sections, which could be used to prevent concurrent accesses. - // This restriction also applies to the higher-level methods fill and drain. - deviceControllerInterruptQueue struct { - queue [configInterruptQueueSize]uintptr // circular queue - head int - count int - } - - deviceControllerCapabilitiesBitmap uint32 - deviceControllerCapabilities struct { - reserved1 uint16 // 15 (bits) - ios uint8 // 1 - maxPacketSize uint16 // 11 - reserved2 uint8 // 2 - zlt uint8 // 1 - mult uint8 // 2 (= 32 bits) - } - - deviceControllerDTDTokenBitmap uint32 - deviceControllerDTDToken struct { - status uint8 // 8 (bits) - reserved1 uint8 // 2 - multiplierOverride uint8 // 2 - reserved2 uint8 // 3 - ioc uint8 // 1 - totalBytes uint16 // 15 - reserved3 uint8 // 1 (= 32 bits) - } - - deviceControllerEndpointStatusBitmap uint32 - deviceControllerEndpointStatus struct { - isOpened uint8 // 1 (bits) - zlt uint8 // 1 - _ uint32 // 30 (= 32 bits) - } - - deviceControllerOriginalBufferBitmap uint32 - deviceControllerOriginalBuffer struct { - originalBufferOffset uint16 // 12 (bits) - originalBufferLength uint32 // 19 - dtdInvalid uint8 // 1 (= 32 bits) - } - - deviceControllerQH struct { - capabilities deviceControllerCapabilitiesBitmap // 4 (bytes) - currentDTDPointer *deviceControllerDTD // 4 - nextDTDPointer *deviceControllerDTD // 4 - dtdToken deviceControllerDTDTokenBitmap // 4 - bufferPointerPage [5]uint32 // 20 - reserved1 uint32 // 4 - setupBuffer deviceSetupBuffer // 8 - setupBufferBack deviceSetupBuffer // 8 - endpointStatus deviceControllerEndpointStatusBitmap // 4 - reserved2 uint32 // 4 (= 64 bytes) - } - - deviceControllerDTDList [2 * configDeviceMaxEndpoints]*deviceControllerDTD - deviceControllerDTD struct { - nextDTDPointer *deviceControllerDTD // 4 (bytes) - dtdToken deviceControllerDTDTokenBitmap // 4 - bufferPointerPage [5]uint32 // 20 - originalBuffer deviceControllerOriginalBufferBitmap // 4 (= 32 bytes) - } -) - -const ( - - // device QH - deviceControllerQHSize = 64 // bytes - deviceControllerQHBufferSize = (configDeviceCount-1)*configDeviceControllerQHAlign + - 2*configDeviceMaxEndpoints*2*deviceControllerQHSize - - deviceControllerQHPointerMsk = 0xFFFFFFC0 - deviceControllerQHMultMsk = 0xC0000000 - deviceControllerQHZLTMsk = 0x20000000 - deviceControllerQHMaxPacketSizeMsk = 0x07FF0000 - deviceControllerQHMaxPacketSize = 0x00000800 - deviceControllerQHIOSMsk = 0x00008000 - - // device DTD - deviceControllerDTDSize = 32 // bytes - deviceControllerDTDBufferSize = (configDeviceCount-1)*configDeviceControllerDTDAlign + - configDeviceControllerMaxDTD*deviceControllerDTDSize - - deviceControllerDTDPointerMsk = 0xFFFFFFE0 - deviceControllerDTDTerminateMsk = 0x00000001 - deviceControllerDTDPageMsk = 0xFFFFF000 - deviceControllerDTDPageOffsetMsk = 0x00000FFF - deviceControllerDTDPageBlock = 0x00001000 - deviceControllerDTDTotalBytesMsk = 0x7FFF0000 - deviceControllerDTDTotalBytes = 0x00004000 - deviceControllerDTDIOCMsk = 0x00008000 - deviceControllerDTDMultIOMsk = 0x00000C00 - deviceControllerDTDStatusMsk = 0x000000FF - deviceControllerDTDStatusErrorMsk = 0x00000068 - deviceControllerDTDStatusActive = 0x00000080 - deviceControllerDTDStatusHalted = 0x00000040 - deviceControllerDTDStatusDataBufferError = 0x00000020 - deviceControllerDTDStatusTransactionError = 0x00000008 -) - -var ( - // special invalid pointer, indicating the end of a list of DTDs - deviceControllerDTDTerminate = (*deviceControllerDTD)(unsafe.Pointer(uintptr( - deviceControllerDTDTerminateMsk))) -) - -// enq enqueues the given mask into tail position of the receiver iq's queue, -// increasing queue length by 1. -// -// When the queue fills to capacity, any subsequent enqueue will overwrite the -// current head with the given value, positioning its following element at the -// front of the queue, and leaves queue length unaffected. -func (iq *deviceControllerInterruptQueue) enq(mask uintptr) { - if iq.count == configInterruptQueueSize { - // queue is full; overwrite oldest element (queue head) and increment head - iq.queue[iq.head] = mask - iq.head++ - iq.head %= configInterruptQueueSize - } else { - // queue is not full; place element at queue tail and increment count - iq.queue[(iq.head+iq.count)%configInterruptQueueSize] = mask - iq.count++ - } -} - -// deq dequeues the mask in tail position from the receiver iq's queue, reducing -// queue length by 1, and returns the dequeued value with true. -// -// When the queue is empty, queue length remains unaffected, and it returns 0 -// with false. -func (iq *deviceControllerInterruptQueue) deq() (uintptr, bool) { - if iq.count == 0 { - // queue is empty; reset head and return an invalid value - iq.head = 0 - return 0, false - } - // queue is not empty; decrement count, reset and return value at queue tail - iq.count-- - n := (iq.head + iq.count) % configInterruptQueueSize - m := iq.queue[n] - iq.queue[n] = 0 // ensure the queue contains no spurious data - return m, true -} - -// fill enqueues each given mask (in order) into tail position of the receiver -// iq's queue, increasing queue length up to capacity, if possible. -// -// If the number of values given is greater than available queue positions, each -// element in head position - at the time the value is enqueued - will be -// overwritten, so that queue length never exceeds capacity, and the element in -// tail position is always the final element given. -func (iq *deviceControllerInterruptQueue) fill(mask ...uintptr) { - for _, m := range mask { - iq.enq(m) - } -} - -// drain dequeues all elements in the receiver iq's queue, reducing queue length -// to 0, and returns the dequeued values (in order) and the number of number of -// values dequeued. -func (iq *deviceControllerInterruptQueue) drain() ( - q [configInterruptQueueSize]uintptr, n int, -) { - for { - m, ok := iq.deq() - if !ok { - return - } - q[n] = m - n++ - } -} - -func getQHBuffer(port uint8, qh int, ep int) *deviceControllerQH { - if port < configDeviceCount && qh < 2 && ep < 2*configDeviceMaxEndpoints { - return (*deviceControllerQH)(unsafe.Pointer( - &deviceControllerQHBuffer[int(port)*configDeviceControllerQHAlign+ - qh*2*configDeviceMaxEndpoints*deviceControllerQHSize+ - ep*deviceControllerQHSize])) - } - return nil -} - -func getDTDBuffer(port uint8, dtd int) *deviceControllerDTD { - if port < configDeviceCount && dtd < configDeviceControllerMaxDTD { - return (*deviceControllerDTD)(unsafe.Pointer( - &deviceControllerDTDBuffer[int(port)*configDeviceControllerDTDAlign+ - dtd*deviceControllerDTDSize])) - } - return nil -} - -func (s deviceControllerCapabilities) pack() deviceControllerCapabilitiesBitmap { - return deviceControllerCapabilitiesBitmap( - ((uint32(s.reserved1) & 0x7FFF) << 0) | // uint16 // 15 (bits) - ((uint32(s.ios) & 0x1) << 15) | // uint8 // 1 - ((uint32(s.maxPacketSize) & 0x7FF) << 16) | // uint16 // 11 - ((uint32(s.reserved2) & 0x3) << 27) | // uint8 // 2 - ((uint32(s.zlt) & 0x1) << 29) | // uint8 // 1 - ((uint32(s.mult) & 0x3) << 30)) // uint8 // 2 (= 32 bits) -} - -func (s deviceControllerDTDToken) pack() deviceControllerDTDTokenBitmap { - return deviceControllerDTDTokenBitmap( - ((uint32(s.status) & 0xFF) << 0) | // uint8 // 8 (bits) - ((uint32(s.reserved1) & 0x3) << 8) | // uint8 // 2 - ((uint32(s.multiplierOverride) & 0x3) << 10) | // uint8 // 2 - ((uint32(s.reserved2) & 0x7) << 12) | // uint8 // 3 - ((uint32(s.ioc) & 0x1) << 15) | // uint8 // 1 - ((uint32(s.totalBytes) & 0x7FFF) << 16) | // uint16 // 15 - ((uint32(s.reserved3) & 0x1) << 31)) // uint8 // 1 (= 32 bits) -} - -func (b deviceControllerDTDTokenBitmap) unpack() deviceControllerDTDToken { - return deviceControllerDTDToken{ - status: uint8(b>>0) & 0xFF, - reserved1: uint8(b>>8) & 0x3, - multiplierOverride: uint8(b>>10) & 0x3, - reserved2: uint8(b>>12) & 0x7, - ioc: uint8(b>>15) & 0x1, - totalBytes: uint16(b>>16) & 0x7FFF, - reserved3: uint8(b>>31) & 0x1, - } -} - -func (s deviceControllerEndpointStatus) pack() deviceControllerEndpointStatusBitmap { - return deviceControllerEndpointStatusBitmap( - ((uint32(s.isOpened) & 0x1) << 0) | // uint8 // 1 (bits) - ((uint32(s.zlt) & 0x1) << 1)) // uint8 // 1 -} - -func (s deviceControllerOriginalBuffer) pack() deviceControllerOriginalBufferBitmap { - return deviceControllerOriginalBufferBitmap( - ((uint32(s.originalBufferOffset) & 0xFFF) << 0) | // uint16 // 12 (bits) - ((uint32(s.originalBufferLength) & 0x7FFFF) << 12) | // uint32 // 19 - ((uint32(s.dtdInvalid) & 0x1) << 31)) // uint8 // 1 (= 32 bits) -} - -func (b deviceControllerOriginalBufferBitmap) unpack() deviceControllerOriginalBuffer { - return deviceControllerOriginalBuffer{ - originalBufferOffset: uint16(b>>0) & 0xFFF, - originalBufferLength: uint32(b>>12) & 0x7FFFF, - dtdInvalid: uint8(b>>31) & 0x1, - } -} - -// cycles converts the given number of microseconds to CPU cycles for a CPU with -// given frequency. -//go:inline -func cycles(microsec, cpuFreqHz uint32) uint32 { - return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000) -} diff --git a/src/machine/usb/device_controller_mimxrt1062.go b/src/machine/usb/device_controller_mimxrt1062.go deleted file mode 100644 index 90ad58f39..000000000 --- a/src/machine/usb/device_controller_mimxrt1062.go +++ /dev/null @@ -1,709 +0,0 @@ -// +build mimxrt1062 - -package usb - -// Implementation of a port controller for USB device mode on NXP iMXRT1062. - -import ( - "device/arm" - "device/nxp" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -// deviceControl represents a USB device controller for NXP iMXRT1062. -// It implements the USB API's deviceController interface. -type deviceControl struct { - port uint8 - device *device - irq interrupt.Interrupt - - messages deviceControllerInterruptQueue - - interruptMask uintptr // interrupt state upon entering critical section - criticalState volatile.Register8 // set to 1 if in critical section, else 0 - - bus *nxp.USB_Type - phy *nxp.USBPHY_Type - nc *nxp.USBNC_Type - qh *deviceControllerQH // The QH structure base address - dtd *deviceControllerDTD // The DTD structure base address - dtdFree *deviceControllerDTD // The idle DTD list head - dtdHead deviceControllerDTDList // The transferring DTD list head for each endpoint - dtdTail deviceControllerDTDList // The transferring DTD list tail for each endpoint - dtdCount uint8 // The idle DTD node count - endpointCount uint8 // The endpoint number of EHCI - isResetting bool // Whether a PORT reset is occurring or not - controllerId uint8 // Controller ID - speed uint8 // Current speed of EHCI - isSuspending bool // Is suspending of the PORT -} - -var ( - // deviceControlInstance holds instances for all USB device controllers - // available on the platform. - deviceControlInstance [configDeviceCount]deviceControl - - //go:align 2048 - deviceControllerQHBuffer [deviceControllerQHBufferSize]uint8 - //go:align 32 - deviceControllerDTDBuffer [deviceControllerDTDBufferSize]uint8 -) - -// We cannot use the sleep timer from this context (import cycle), but we need -// an approximate method to spin CPU cycles for short periods of time. -//go:inline -func delayMicrosec(microsec uint32) { - n := cycles(microsec, configCPUFrequencyHz) - for i := uint32(0); i < n; i++ { - arm.Asm(`nop`) - } -} - -// initController returns a deviceController for the receiver USB device. -// It allocates the registers and installs/enables an interrupt handler for -// the receiver USB device. It also initializes the shared buffers used by the -// USB controller hardware. -func (d *device) initController() deviceController { - - dc := &deviceControlInstance[d.port] - - dc.port = d.port - dc.device = d - - // based on the selected port, install interrupt handler and initialize - // register references - switch d.port { - case 0: - dc.irq = interrupt.New(nxp.IRQ_USB_OTG1, func(interrupt.Interrupt) { - portInstance[0].device.controller.interrupt() - }) - dc.bus = nxp.USB1 - dc.phy = nxp.USBPHY1 - dc.nc = nxp.USBNC1 - case 1: - dc.irq = interrupt.New(nxp.IRQ_USB_OTG2, func(interrupt.Interrupt) { - //portInstance[1].device.controller.interrupt() - }) - dc.bus = nxp.USB2 - dc.phy = nxp.USBPHY2 - dc.nc = nxp.USBNC2 - } - - // get base address of QH and DTD buffers - dc.qh = (*deviceControllerQH)(unsafe.Pointer( - &deviceControllerQHBuffer[int(d.port)*configDeviceControllerQHAlign])) - dc.dtd = (*deviceControllerDTD)(unsafe.Pointer( - &deviceControllerDTDBuffer[int(d.port)*configDeviceControllerDTDAlign])) - - dc.irq.SetPriority(configInterruptPriority) - dc.irq.Enable() - - return dc -} - -// init initializes the USB device subsystem for the receiver deviceControl. -func (dc *deviceControl) init() status { - - // reset the controller - dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_RST) - for dc.bus.USBCMD.HasBits(nxp.USB_USBCMD_RST) { - } - - // get hardware's endpoint count - dc.endpointCount = uint8(dc.bus.DCCPARAMS.Get() & nxp.USB_DCCPARAMS_DEN_Msk) - if dc.endpointCount < configDeviceMaxEndpoints { - return statusError - } - - // clear the controller mode field and set to device mode: - // controller mode (CM) 0x0=idle, 0x2=device-only, 0x3=host-only - dc.bus.USBMODE.ReplaceBits(nxp.USB_USBMODE_CM_CM_2, - nxp.USB_USBMODE_CM_Msk>>nxp.USB_USBMODE_CM_Pos, nxp.USB_USBMODE_CM_Pos) - - // reset the constroller state to default - return dc.resetState() -} - -func (dc *deviceControl) deinit() status { - return statusSuccess -} - -func (dc *deviceControl) enable(enable bool) status { - if enable { - // ensure D+ pulled down long enough for host to detect previous disconnect - delayMicrosec(5000) - return dc.control(deviceControlRun, nil) - } else { - return dc.control(deviceControlStop, nil) - } -} - -// interrupt is the base interrupt handler for all USB device interrupts. -func (dc *deviceControl) interrupt() { - - // protect access to message queue - for statusRetry == dc.critical(true) { - } - - // read and clear the interrupts that fired - status := dc.bus.USBSTS.Get() & dc.bus.USBINTR.Get() - dc.bus.USBSTS.Set(status) - - // enqueue interrupts for runtime processing - dc.messages.enq(uintptr(status)) - - // release message queue - _ = dc.critical(false) -} - -func (dc *deviceControl) process() status { - - // protect access to message queue - if dc.critical(true).OK() { - - // dequeue oldest interrupt in message queue - status, ok := dc.messages.deq() - - // release message queue - _ = dc.critical(false) - - // process message if queue was not empty - if ok { - - if 0 != (status & nxp.USB_USBSTS_URI_Msk) { // USB reset - dc.reset() - } - - if 0 != (status & nxp.USB_USBSTS_UI_Msk) { // USB token done - dc.tokenDone() - } - - if 0 != (status & nxp.USB_USBSTS_PCI_Msk) { // USB port status change - dc.portChange() - } - - if 0 != (status & nxp.USB_USBSTS_SRI_Msk) { // USB start of frame (SOF) - dc.frameStart() - } - } - - // message queue read and processed - return statusSuccess - } - - // could not acquire lock on message queue - return statusBusy -} - -func (dc *deviceControl) transfer(address uint8, buffer []uint8, length uint32) status { - - if dc.isResetting { - return statusError - } - - endpoint, direction := unpackEndpoint(address) - endpointIndex := int((endpoint << 1) | direction) - currentIndex := 0 - - primeBit := uint32(1) << ((address & specDescriptorEndpointAddressNumberMsk) + - ((address & specDescriptorEndpointAddressDirectionMsk) >> 3)) - epStatus, qhIdle := primeBit, false - - qh := getQHBuffer(dc.port, 0, endpointIndex) - if 0 == qh.endpointStatus&0x1 { // bit 0: isOpened - return statusError - } - - dtdRequestCount := (length + deviceControllerDTDTotalBytes - 1) / - deviceControllerDTDTotalBytes - if 0 == dtdRequestCount { - dtdRequestCount = 1 - } - - if dtdRequestCount > uint32(dc.dtdCount) { - return statusBusy - } - - var ( - dtdHead *deviceControllerDTD - sendLength uint32 - ) - - for { - - // limit transfer length to total DTD bytes - sendLength = length - if length > deviceControllerDTDTotalBytes { - sendLength = deviceControllerDTDTotalBytes - } - length -= sendLength - - // select a free DTD - dtd := dc.dtdFree - dc.dtdFree = dtd.nextDTDPointer - dc.dtdCount-- - - // save DTD head when current active buffer offset is 0 - if 0 == currentIndex { - dtdHead = dtd - } - - // set DTD field - dtd.nextDTDPointer = deviceControllerDTDTerminate - dtd.bufferPointerPage[0] = - uint32(uintptr(unsafe.Pointer(&buffer[0]))) + uint32(currentIndex) - dtd.bufferPointerPage[1] = - (dtd.bufferPointerPage[0] + deviceControllerDTDPageBlock) & deviceControllerDTDPageMsk - dtd.bufferPointerPage[2] = - dtd.bufferPointerPage[1] + deviceControllerDTDPageBlock - dtd.bufferPointerPage[3] = - dtd.bufferPointerPage[2] + deviceControllerDTDPageBlock - dtd.bufferPointerPage[4] = - dtd.bufferPointerPage[3] + deviceControllerDTDPageBlock - - // save original buffer and length to transfer - dtd.originalBuffer = deviceControllerOriginalBuffer{ - originalBufferOffset: uint16(dtd.bufferPointerPage[0]) & - deviceControllerDTDPageOffsetMsk, - originalBufferLength: sendLength, - dtdInvalid: 0, - }.pack() - - // set IOC field in final DTD - ioc := uint8(0) - if 0 == length { - ioc = 1 - } - // set DTD active flag - dtd.dtdToken = deviceControllerDTDToken{ - status: deviceControllerDTDStatusActive, - ioc: ioc, - totalBytes: uint16(sendLength), - }.pack() - - // update buffer offset - currentIndex += int(sendLength) - - // add DTD to in-use queue - if nil != dc.dtdTail[endpointIndex] { - dc.dtdTail[endpointIndex].nextDTDPointer = dtd - dc.dtdTail[endpointIndex] = dtd - } else { - dc.dtdHead[endpointIndex] = dtd - dc.dtdTail[endpointIndex] = dtd - qhIdle = true - } - - if 0 == length { - break - } - } - - if specEndpointControl == endpoint && specIn == direction { - // get last setup packet - setupIndex := int(endpoint << 1) - setupQH := getQHBuffer(dc.port, 0, setupIndex) - setupMaxSize := uint32(setupQH.capabilities&0x07FF0000) >> 16 // bits 15-26: maxPacketSize - var setup deviceSetup - setup.parse(setupQH.setupBufferBack[:]) - if 0 != qh.endpointStatus&0x2 { // bit 1: ZLT - if (0 != sendLength) && (sendLength < uint32(setup.wLength)) && - (0 == (sendLength % setupMaxSize)) { - // enable ZLT (zlt==0) - setupQH.capabilities &^= deviceControllerCapabilities{zlt: 1}.pack() - } - } - } - - // check if QH is empty - if !qhIdle { - // if prime bit is set, nothing left to do - if dc.bus.ENDPTPRIME.HasBits(primeBit) { - return statusSuccess - } - // wait to safely transmit DTD - for { - dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_ATDTW) - _ = dc.bus.ENDPTSTAT.Get() // read-clear endpoint status register - if dc.bus.USBCMD.HasBits(nxp.USB_USBCMD_ATDTW) { - break - } - } - dc.bus.USBCMD.ClearBits(nxp.USB_USBCMD_ATDTW) - } - - // if QH is empty or the endpoint is not primed, need to link current DTD head - // to the QH. if endpoint is not primed and qhIdle is false, QH is empty. - if qhIdle || 0 == epStatus&primeBit { - qh.nextDTDPointer = dtdHead - qh.dtdToken = 0 - dc.bus.ENDPTPRIME.Set(primeBit) - primeAttempt := 0 - for !dc.bus.ENDPTSTAT.HasBits(primeBit) { - if primeAttempt++; primeAttempt >= configDeviceControllerMaxPrimeAttempts { - return statusError - } - if dc.bus.ENDPTCOMPLETE.HasBits(primeBit) { - break - } - dc.bus.ENDPTPRIME.Set(primeBit) - } - } - - return statusSuccess -} - -func (dc *deviceControl) send(address uint8, buffer []uint8, length uint32) status { - return dc.transfer((address&specDescriptorEndpointAddressNumberMsk)| - (specDescriptorEndpointAddressDirectionIn), buffer, length) -} - -func (dc *deviceControl) receive(address uint8, buffer []uint8, length uint32) status { - return dc.transfer((address&specDescriptorEndpointAddressNumberMsk)| - (specDescriptorEndpointAddressDirectionOut), buffer, length) -} - -func (dc *deviceControl) cancel(address uint8) status { - return statusSuccess -} - -func (dc *deviceControl) control(command deviceControlID, param interface{}) (s status) { - - // assume success unless error condition deliberately detected - s = statusSuccess - - switch command { - case deviceControlRun: - dc.bus.USBCMD.SetBits(nxp.USB_USBCMD_RS) - - case deviceControlStop: - dc.bus.USBCMD.ClearBits(nxp.USB_USBCMD_RS) - - case deviceControlEndpointInit: - config, ok := param.(*deviceEndpointConfig) - if !ok { - return statusInvalidParameter - } - s = dc.initEndpoint(config) - - case deviceControlEndpointDeinit: - address, ok := param.(uint8) - if !ok { - return statusInvalidParameter - } - s = dc.deinitEndpoint(address) - - case deviceControlEndpointStall: - address, ok := param.(uint8) - if !ok { - return statusInvalidParameter - } - s = dc.stallEndpoint(address) - - case deviceControlEndpointUnstall: - address, ok := param.(uint8) - if !ok { - return statusInvalidParameter - } - s = dc.unstallEndpoint(address) - - case deviceControlGetDeviceStatus: - // param should be a pointer to uint16, acting as output parameter. - stat, ok := param.(*uint16) - if !ok { - return statusInvalidParameter - } - // configDeviceSelfPowered is a configuration constant on iMXRT1062 - *stat = configDeviceSelfPowered << - specRequestStandardGetStatusDeviceSelfPoweredPos - - case deviceControlGetEndpointStatus: - // param should be pointer to deviceEndpointStatus, acting as output - // parameter. - stat, ok := param.(*deviceEndpointStatus) - if !ok { - return statusInvalidParameter - } - endpoint, direction := unpackEndpoint(stat.address) - if endpoint >= configDeviceMaxEndpoints { - return statusInvalidParameter - } - mask := uint32(nxp.USB_ENDPTCTRL0_RXS) - if specOut != direction { - mask = nxp.USB_ENDPTCTRL0_TXS - } - ctrl := dc.endpointControlRegister(endpoint) - if nil == ctrl { - return statusInvalidParameter - } - if ctrl.HasBits(mask) { - stat.status = uint16(deviceEndpointStateStalled) - } else { - stat.status = uint16(deviceEndpointStateIdle) - } - - case deviceControlPreSetDeviceAddress: - address, ok := param.(uint8) - if !ok { - return statusInvalidParameter - } - dc.bus.DEVICEADDR.Set((uint32(address) << nxp.USB_DEVICEADDR_USBADR_Pos) | - nxp.USB_DEVICEADDR_USBADRA_Msk) - - case deviceControlSetDeviceAddress: - // TODO - - case deviceControlGetSynchFrame: - return statusNotSupported - - case deviceControlSetDefaultStatus: - for i := uint8(0); i < configDeviceMaxEndpoints; i++ { - _ = dc.deinitEndpoint(i | specDescriptorEndpointAddressDirectionIn) - _ = dc.deinitEndpoint(i | specDescriptorEndpointAddressDirectionOut) - } - s = dc.resetState() - - case deviceControlGetSpeed: - // param should be a pointer to uint8, acting as output parameter. - speed, ok := param.(*uint8) - if !ok { - return statusInvalidParameter - } - *speed = dc.speed - - case deviceControlGetOTGStatus: - return statusNotSupported - - case deviceControlSetOTGStatus: - return statusNotSupported - } - - return -} - -func (dc *deviceControl) critical(enter bool) status { - if enter { - // check if critical section already locked - if dc.criticalState.Get() != 0 { - return statusRetry - } - // lock critical section - dc.criticalState.Set(1) - // disable interrupts, storing state in receiver - dc.interruptMask = arm.DisableInterrupts() - } else { - // ensure critical section is locked - if dc.criticalState.Get() != 0 { - // re-enable interrupts, using state stored in receiver - arm.EnableInterrupts(dc.interruptMask) - // unlock critical section - dc.criticalState.Set(0) - } - } - return statusSuccess -} - -func (dc *deviceControl) resetState() status { - - dc.dtdFree = dc.dtd - p := dc.dtdFree - for i := 1; i < configDeviceControllerMaxDTD; i++ { - p.nextDTDPointer = getDTDBuffer(dc.port, i) - p = p.nextDTDPointer - } - p.nextDTDPointer = nil - dc.dtdCount = configDeviceControllerMaxDTD - - // no interrupt threshold - dc.bus.USBCMD.ClearBits(nxp.USB_USBCMD_ITC_Msk) - - // disable setup lockout - dc.bus.USBMODE.SetBits(nxp.USB_USBMODE_SLOM_Msk) - - // use little-endianness - dc.bus.USBMODE.ClearBits(nxp.USB_USBMODE_ES_Msk) - - for i := 0; i < 2*configDeviceMaxEndpoints; i++ { - qh := getQHBuffer(dc.port, 0, i) - qh.capabilities = - deviceControllerCapabilities{ - maxPacketSize: configDeviceControllerMaxPacketSize, - }.pack() - qh.endpointStatus = - deviceControllerEndpointStatus{ - isOpened: 0, - }.pack() - qh.nextDTDPointer = deviceControllerDTDTerminate - dc.dtdHead[i] = nil - dc.dtdTail[i] = nil - } - dc.bus.ASYNCLISTADDR.Set(uint32(uintptr(unsafe.Pointer( - getQHBuffer(dc.port, 0, 0))))) - - dc.bus.DEVICEADDR.Set(0) - - // enable interrupts: bus enable, bus error, port change detect, bus reset - dc.bus.USBINTR.Set(nxp.USB_USBINTR_UE_Msk | nxp.USB_USBINTR_UEE_Msk | - nxp.USB_USBINTR_PCE_Msk | nxp.USB_USBINTR_URE_Msk) - - dc.isResetting = false - - return statusSuccess -} - -func (dc *deviceControl) reset() { - - println("reset") - - // clear setup flag - dc.bus.ENDPTSETUPSTAT.Set(dc.bus.ENDPTSETUPSTAT.Get()) - // clear endpoint complete flag - dc.bus.ENDPTCOMPLETE.Set(dc.bus.ENDPTCOMPLETE.Get()) - - // flush any pending transfers - for dc.bus.ENDPTPRIME.HasBits(nxp.USB_ENDPTPRIME_PERB_Msk | nxp.USB_ENDPTPRIME_PETB_Msk) { - dc.bus.ENDPTFLUSH.Set(nxp.USB_ENDPTFLUSH_FERB_Msk | nxp.USB_ENDPTFLUSH_FETB_Msk) - } - - // set receiver flag if port reset bit is set; otherwise, notify device class. - if dc.bus.PORTSC1.HasBits(nxp.USB_PORTSC1_PR_Msk) { - dc.isResetting = true - } else { - // send reset notification to common device - dc.device.notify(deviceNotification{code: deviceNotifyBusReset}) - } -} - -func (dc *deviceControl) tokenDone() { - println("token done") -} - -func (dc *deviceControl) portChange() { - // check if port is resetting - if !dc.bus.PORTSC1.HasBits(nxp.USB_PORTSC1_PR) { - // not resetting, update bus speed - if dc.bus.PORTSC1.HasBits(nxp.USB_PORTSC1_HSP) { - dc.speed = specSpeedHigh - } else { - dc.speed = specSpeedFull - } - // if reset flag is set, notify device layer reset has finished - if dc.isResetting { - dc.device.notify( - deviceNotification{ - buffer: nil, - length: 0, - code: deviceNotifyBusReset, - isSetup: false, - }) - dc.isResetting = false - } - } -} - -func (dc *deviceControl) frameStart() { - println("frame start") -} - -func (dc *deviceControl) endpointControlRegister(endpoint uint8) *volatile.Register32 { - endpoint &= specDescriptorEndpointAddressNumberMsk - if endpoint < configDeviceMaxEndpoints { - switch endpoint { - case 0: - return &dc.bus.ENDPTCTRL0 - case 1: - return &dc.bus.ENDPTCTRL1 - case 2: - return &dc.bus.ENDPTCTRL2 - case 3: - return &dc.bus.ENDPTCTRL3 - case 4: - return &dc.bus.ENDPTCTRL4 - case 5: - return &dc.bus.ENDPTCTRL5 - case 6: - return &dc.bus.ENDPTCTRL6 - case 7: - return &dc.bus.ENDPTCTRL7 - } - } - return nil -} - -func (dc *deviceControl) cancelControlPipe(endpoint, direction uint8) status { - index := (endpoint << 1) + direction - message := deviceNotification{ - buffer: nil, - length: 0, - } - - // get DTD of control pipe - currentDTD := (*deviceControllerDTD)(unsafe.Pointer( - uintptr(unsafe.Pointer(dc.dtdHead[index])) & deviceControllerDTDPointerMsk)) - - for nil != currentDTD { - originalBuffer := currentDTD.originalBuffer.unpack() - dtdToken := currentDTD.dtdToken.unpack() - - // pass transfer buffer address - if nil == message.buffer { - message.buffer = *(*[]uint8)(unsafe.Pointer( - uintptr((currentDTD.bufferPointerPage[0] & deviceControllerDTDPageMsk) | - uint32(originalBuffer.originalBufferOffset)))) - } - if 0 != dtdToken.status&deviceControllerDTDStatusActive { - message.length = packU32(deviceCDCACMBufferInvalid32) - } else { - message.length += originalBuffer.originalBufferLength - uint32(dtdToken.totalBytes) - } - - if dc.dtdHead[index] == dc.dtdTail[index] { - dc.dtdHead[index] = nil - dc.dtdTail[index] = nil - qh := getQHBuffer(dc.port, 0, int(index)) - qh.nextDTDPointer = deviceControllerDTDTerminate - qh.dtdToken = 0 - } else { - dc.dtdHead[index] = dc.dtdHead[index].nextDTDPointer - } - - if 0 != currentDTD.dtdToken.unpack().ioc || - 0 == uintptr(unsafe.Pointer(dc.dtdHead[index]))&deviceControllerDTDPointerMsk { - message.code = deviceNotificationID(endpoint | - (direction << specDescriptorEndpointAddressDirectionPos)) - message.isSetup = false - dc.device.notify(message) - message.buffer = nil - message.length = 0 - } - - currentDTD.dtdToken = 0 - currentDTD.nextDTDPointer = dc.dtdFree - dc.dtdFree = currentDTD - dc.dtdCount++ - - // get DTD of control pipe - currentDTD = (*deviceControllerDTD)(unsafe.Pointer( - uintptr(unsafe.Pointer(dc.dtdHead[index])) & deviceControllerDTDPointerMsk)) - - } - return statusSuccess -} - -func (dc *deviceControl) initEndpoint(config *deviceEndpointConfig) status { - return statusSuccess -} - -func (dc *deviceControl) deinitEndpoint(address uint8) status { - return statusSuccess -} - -func (dc *deviceControl) stallEndpoint(address uint8) status { - return statusSuccess -} - -func (dc *deviceControl) unstallEndpoint(address uint8) status { - return statusSuccess -} diff --git a/src/machine/usb2/hcd.go b/src/machine/usb/hcd.go similarity index 91% rename from src/machine/usb2/hcd.go rename to src/machine/usb/hcd.go index 21dc170b2..366bdcc9e 100644 --- a/src/machine/usb2/hcd.go +++ b/src/machine/usb/hcd.go @@ -1,4 +1,4 @@ -package usb2 +package usb type hcd interface { class() class diff --git a/src/machine/usb2/hcd_mimxrt1062.go b/src/machine/usb/hcd_mimxrt1062.go similarity index 99% rename from src/machine/usb2/hcd_mimxrt1062.go rename to src/machine/usb/hcd_mimxrt1062.go index 7d39fa78a..1282765e6 100644 --- a/src/machine/usb2/hcd_mimxrt1062.go +++ b/src/machine/usb/hcd_mimxrt1062.go @@ -1,6 +1,6 @@ // +build mimxrt1062 -package usb2 +package usb // Implementation of USB host controller driver (hcd) for NXP iMXRT1062. diff --git a/src/machine/usb/host.go b/src/machine/usb/host.go deleted file mode 100644 index 61a13886c..000000000 --- a/src/machine/usb/host.go +++ /dev/null @@ -1,25 +0,0 @@ -package usb - -// Unexported USB device type definitions. -// In device mode, a USB device represents the whole USB port controller. -// In host mode, a USB device represents a peripheral device connected to the -// USB port controller. -type ( - host struct { - port uint8 - } -) - -func (h *host) init(port uint8) (s status) { - - // initialize host - h.port = port - - return statusSuccess -} - -func (h *host) deinit() status { - - // de-initialize host - return statusSuccess -} diff --git a/src/machine/usb/host_controller.go b/src/machine/usb/host_controller.go deleted file mode 100644 index c4a6ff719..000000000 --- a/src/machine/usb/host_controller.go +++ /dev/null @@ -1,13 +0,0 @@ -package usb - -// hostController provides hardware abstraction over a platform's physical -// USB host port controller (e.g., an EHCI-compliant peripheral). -// -// To connect the USB 2.0 host driver stack to a particular platform, the -// following method must be implemented: -// -// func (h *host) initController() hostController -// -// This method shall return an implementation of hostController, or nil if a -// controller cannot be allocated for the given port. -type hostController interface{} diff --git a/src/machine/usb/spec.go b/src/machine/usb/spec.go deleted file mode 100644 index 856deb36c..000000000 --- a/src/machine/usb/spec.go +++ /dev/null @@ -1,167 +0,0 @@ -package usb - -// Constants defined per USB 2.0 specification. -const ( - // USB speed - specSpeedFull = 0x00 - specSpeedLow = 0x01 - specSpeedHigh = 0x02 - specSpeedSuper = 0x04 - - // USB standard descriptor endpoint type - specEndpointControl = 0x00 - specEndpointIsochronous = 0x01 - specEndpointBulk = 0x02 - specEndpointInterrupt = 0x03 - - // USB standard descriptor transfer direction - specOut = 0 - specIn = 1 - - // USB standard descriptor length - specDescriptorLengthDevice = 18 - specDescriptorLengthConfigure = 9 - specDescriptorLengthInterface = 9 - specDescriptorLengthEndpoint = 7 - specDescriptorLengthEndpointCompanion = 6 - specDescriptorLengthDeviceQualitier = 10 - specDescriptorLengthOTGDescriptor = 5 - specDescriptorLengthBOSDescriptor = 5 - specDescriptorLengthDeviceCapabilityUSB20Extension = 7 - specDescriptorLengthDeviceCapabilitySuperspeed = 10 - - // USB device capability type codes - specDescriptorTypeDeviceCapabilityWireless = 0x01 - specDescriptorTypeDeviceCapabilityUSB20Extension = 0x02 - specDescriptorTypeDeviceCapabilitySuperspeed = 0x03 - - // USB standard descriptor type - specDescriptorTypeDevice = 0x01 - specDescriptorTypeConfigure = 0x02 - specDescriptorTypeString = 0x03 - specDescriptorTypeInterface = 0x04 - specDescriptorTypeEndpoint = 0x05 - specDescriptorTypeDeviceQualitier = 0x06 - specDescriptorTypeOtherSpeedConfiguration = 0x07 - specDescriptorTypeInterfaacePower = 0x08 - specDescriptorTypeOTG = 0x09 - specDescriptorTypeInterfaceAssociation = 0x0B - specDescriptorTypeBOS = 0x0F - specDescriptorTypeDeviceCapability = 0x10 - - specDescriptorTypeHID = 0x21 - specDescriptorTypeHIDReport = 0x22 - specDescriptorTypeHIDPhysical = 0x23 - - specDescriptorTypeCDCInterface = 0x24 - specDescriptorTypeCDCEndpoint = 0x25 - - specDescriptorTypeEndpointCompanion = 0x30 - - // USB standard request type - specRequestTypeDirMsk = 0x80 - specRequestTypeDirPos = 7 - specRequestTypeDirOut = 0x00 - specRequestTypeDirIn = 0x80 - - specRequestTypeTypeMsk = 0x60 - specRequestTypeTypePos = 5 - specRequestTypeTypeStandard = 0 - specRequestTypeTypeClass = 0x20 - specRequestTypeTypeVendor = 0x40 - - specRequestTypeRecipientMsk = 0x1F - specRequestTypeRecipientPos = 0 - specRequestTypeRecipientDevice = 0x00 - specRequestTypeRecipientInterface = 0x01 - specRequestTypeRecipientEndpoint = 0x02 - specRequestTypeRecipientOther = 0x03 - - // USB standard request - specRequestStandardGetStatus = 0x00 - specRequestStandardClearFeature = 0x01 - specRequestStandardSetFeature = 0x03 - specRequestStandardSetAddress = 0x05 - specRequestStandardGetDescriptor = 0x06 - specRequestStandardSetDescriptor = 0x07 - specRequestStandardGetConfiguration = 0x08 - specRequestStandardSetConfiguration = 0x09 - specRequestStandardGetInterface = 0x0A - specRequestStandardSetInterface = 0x0B - specRequestStandardSynchFrame = 0x0C - - // USB standard request: GET status - specRequestStandardGetStatusDeviceSelfPoweredPos = 0 - specRequestStandardGetStatusDeviceRemoteWakeupPos = 1 - - specRequestStandardGetStatusEndpointHaltMsk = 0x01 - specRequestStandardGetStatusEndpointHaltPos = 0 - - specRequestStandardGetStatusOTGStatusSelector = 0xF000 - - // USB standard request: CLEAR/SET feature - specRequestStandardFeatureSelectorEndpointHalt = 0 - specRequestStandardFeatureSelectorDeviceRemoteWakeup = 1 - specRequestStandardFeatureSelectorDeviceTestMode = 2 - specRequestStandardFeatureSelectorBHNPEnable = 3 - specRequestStandardFeatureSelectorAHNPSupport = 4 - specRequestStandardFeatureSelectorAAltHNPSupport = 5 - - // USB standard descriptor: configure attributes - specDescriptorConfigureAttributeD7Msk = 0x80 - specDescriptorConfigureAttributeD7Pos = 7 - - specDescriptorConfigureAttributeSelfPoweredMsk = 0x40 - specDescriptorConfigureAttributeSelfPoweredPos = 6 - - specDescriptorConfigureAttributeRemoteWakeupMsk = 0x20 - specDescriptorConfigureAttributeRemoteWakeupPos = 5 - - // USB standard descriptor: endpoint attributes - specDescriptorEndpointAddressDirectionMsk = 0x80 - specDescriptorEndpointAddressDirectionPos = 7 - specDescriptorEndpointAddressDirectionOut = 0 - specDescriptorEndpointAddressDirectionIn = 0x80 - - specDescriptorEndpointAddressNumberMsk = 0x0F - specDescriptorEndpointAddressNumberPos = 0 - - specDescriptorEndpointAttributeTypeMsk = 0x03 - specDescriptorEndpointAttributeNumberPos = 0 - - specDescriptorEndpointAttributeSyncTypeMsk = 0x0C - specDescriptorEndpointAttributeSyncTypePos = 2 - specDescriptorEndpointAttributeSyncTypeNoSync = 0x00 - specDescriptorEndpointAttributeSyncTypeAsync = 0x04 - specDescriptorEndpointAttributeSyncTypeAdaptive = 0x08 - specDescriptorEndpointAttributeSyncTypeSync = 0x0C - - specDescriptorEndpointAttributeUsageTypeMsk = 0x30 - specDescriptorEndpointAttributeUsageTypePos = 4 - specDescriptorEndpointAttributeUsageTypeDataEndpoint = 0x00 - specDescriptorEndpointAttributeUsageTypeFeedbackEndpoint = 0x10 - specDescriptorEndpointAttributeUsageTypeImplicitFeedbackDataEndpoint = 0x20 - - specDescriptorEndpointMaxpacketsizeSizeMsk = 0x07FF - specDescriptorEndpointMaxpacketsizeMultTransactionsMsk = 0x1800 - specDescriptorEndpointMaxpacketsizeMultTransactionsPos = 11 - - // USB standard descriptor: OTG attributes - specDescriptorOTGAttributesSRPMsk = 0x01 - specDescriptorOTGAttributesHNPMsk = 0x02 - specDescriptorOTGAttributesADPMsk = 0x04 - - // USB standard descriptor: device capability attributes (USB 2.0 extension) - specDescriptorDeviceCapabilityUSB20ExtensionLPMMsk = 0x02 - specDescriptorDeviceCapabilityUSB20ExtensionLPMPos = 1 - specDescriptorDeviceCapabilityUSB20ExtensionBESLMsk = 0x04 - specDescriptorDeviceCapabilityUSB20ExtensionBESLPos = 2 -) - -//go:inline -func unpackEndpoint(address uint8) (number, direction uint8) { - return (address & specDescriptorEndpointAddressNumberMsk) >> - specDescriptorEndpointAddressNumberPos, - (address & specDescriptorEndpointAddressDirectionMsk) >> - specDescriptorEndpointAddressDirectionPos -} diff --git a/src/machine/usb/uart.go b/src/machine/usb/uart.go index 1925aea59..a5ea35c05 100644 --- a/src/machine/usb/uart.go +++ b/src/machine/usb/uart.go @@ -5,7 +5,10 @@ import ( ) var ( - ErrInvalidPort = errors.New("invalid USB port") + ErrUARTInvalidPort = errors.New("invalid USB port") + ErrUARTInvalidCore = errors.New("invalid USB core") + ErrUARTEmptyBuffer = errors.New("USB receive buffer empty") + ErrUARTWriteFailed = errors.New("USB write failure") ) type ( @@ -16,351 +19,75 @@ type ( // UART represents a virtual serial (UART) device emulation using the USB // CDC-ACM device class driver. UART struct { - port uint8 // USB port (core index, e.g., 0-1) - desc *ConfigDeviceDescriptor // User-provided USB device descriptor information - class *deviceClass // USB device class handle - acm *deviceCDCACM // USB CDC-ACM device class handle - - attached bool - transact bool - config uint8 // selected configuration index (1-based, 0=invalid) - speed uint8 // enumerated bus speed (low, full, high) - alternate deviceCDCACMAlternateList + port int // USB port (core index, e.g., 0-1) + core *core } ) -var ( - uartAbstractState = []uint8{0x00, 0x00} - uartCountryCode = []uint8{0x00, 0x00} -) - -func (uart *UART) SetPort(port uint8) { - if port >= ConfigPortCount || port >= configDeviceCount || - port >= configDeviceCDCACMCount { - return // invalid port for USB CDC-ACM device class - } - // TODO: if changed, may need to reset port controller and tell host to - // re-enumerate devices - uart.port = port -} - -func (uart *UART) SetDeviceDescriptor(desc *ConfigDeviceDescriptor) { - if nil == desc { - return // invalid device descriptor information - } - // TODO: if changed, may need to reset port controller and tell host to - // re-enumerate devices - uart.desc = desc -} - func (uart *UART) Configure(config UARTConfig) error { - if uart.port >= ConfigPortCount || uart.port >= configDeviceCount || - uart.port >= configDeviceCDCACMCount { - return ErrInvalidPort - } - - // use default configuration index (1-based index; 0=invalid) - uart.config = configDeviceCDCACMConfigurationIndex - - // modify the global basic configuration struct configDeviceCDCACM for our USB - // port and configuration index. - // - // these settings are copied into the real CDC-ACM object, using interface - // deviceClassDriver, via initialization method (*deviceCDCACM).init(). - - // change baud rate from default, if provided - if config.BaudRate != 0 { - configDeviceCDCACM[uart.port][uart.config-1].lineCodingBaudRate = - config.BaudRate + if uart.port >= CoreCount || uart.port >= dcdCount { + return ErrUARTInvalidPort } // verify we have a free USB port and take ownership of it - port, status := initPort(uart.port, modeDevice) - if !status.OK() { - return status + var st status + uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1}) + if !st.ok() { + return ErrUARTInvalidPort } - - // apply the CDC-ACM configuration to our port - uart.acm, uart.class = port.initCDCACM(uart.config, uart) - - // enable USB device mode functionality, which allows a host to enumerate us - status = port.device.controller.enable(true) - if !status.OK() { - return status - } - return nil } -func (uart *UART) deviceEvent(ev deviceEventID, param interface{}) status { - - switch ev { - case deviceEventBusReset: - uart.attached = false - uart.config = 0 // clear selected configuration (1-based index) - s := uart.acm.device.busSpeed(&uart.speed) - if s.OK() { - s = uart.acm.device.setBusSpeed(uart.speed) - } - return s - - case deviceEventSetConfiguration: - if id, ok := param.(uint8); ok { - if 0 == id { - uart.attached = false - uart.config = 0 // clear selected configuration (1-based index) - return statusSuccess - } - // verify we have a config struct at given index - if nil != uart.class && nil != uart.class.config && - int(id) <= len(uart.class.config) && - int(id) <= len(configDeviceCDCACM[uart.port]) { - config := uart.class.config[id-1] // receiver configuration - system := configDeviceCDCACM[uart.port][id-1] // platform configuration - // verify the config is a CDC device and has a defined driver - if deviceClassCDC == config.info.classID && nil != config.driver { - // finally, verify the config driver is an ACM device driver - if _, ok := config.driver.(*deviceCDCACM); ok { - uart.attached = true - uart.config = id - return uart.acm.receive(system.dataBulkOutEndpoint, uart.acm.recvBuffer[:], - uint32(system.dataBulkOutPacketSize)) - } - } - } - } - return statusNotSupported // all non-error paths return early - - case deviceEventSetInterface: - if uart.attached { - if setting, ok := param.(uint16); ok { - inf := (setting & 0xFF00) >> 8 - if inf < configDeviceCDCACMInterfaceCount { - uart.alternate[inf] = setting & 0x00FF - } - } - } - - case deviceEventGetConfiguration: - case deviceEventGetInterface: - case deviceEventGetDeviceDescriptor: - case deviceEventGetConfigurationDescriptor: - case deviceEventGetStringDescriptor: +// Buffered returns the number of bytes currently stored in the RX buffer. +func (uart UART) Buffered() int { + dc, ok := uart.core.dc.(*deviceController) + if !ok { + return 0 } - - return statusSuccess + return dc.uartAvailable() } -func (uart *UART) classEvent(ev uint32, param interface{}) status { - - if nil == uart.acm { - return statusInvalidHandle +// 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) { + dc, ok := uart.core.dc.(*deviceController) + if !ok { + return 0, ErrUARTInvalidCore } - - switch deviceCDCACMEventID(ev) { - case deviceCDCACMEventSendResponse: - if ctl, ok := param.(deviceEndpointControlMessage); ok { - - // verify receiver configuration - if int(uart.port) >= len(configDeviceCDCACM) || uart.config == 0 || - int(uart.config) > len(configDeviceCDCACM[uart.port]) { - return statusNotSupported - } - // get platform configuration - system := configDeviceCDCACM[uart.port][uart.config-1] - - if ctl.length > 0 && 0 != ctl.length%uint32(system.dataBulkInPacketSize) { - // If the last packet is the size of endpoint, then send an additional - // zero-ended packet to notify the host it may flush output. - return uart.acm.send(system.dataBulkInEndpoint, nil, 0) - } - - if uart.attached && uart.transact && - (nil != ctl.buffer || (nil == ctl.buffer && 0 == ctl.length)) { - // send complete, schedule buffer for next receive event - return uart.acm.receive(system.dataBulkOutEndpoint, uart.acm.recvBuffer[:], - uint32(system.dataBulkOutPacketSize)) - } - } - return statusError // all non-error paths return early - - case deviceCDCACMEventRecvResponse: - if ctl, ok := param.(deviceEndpointControlMessage); ok { - if uart.attached && uart.transact { - uart.acm.recvSize = ctl.length - if 0 == ctl.length { - - // verify receiver configuration - if int(uart.port) >= len(configDeviceCDCACM) || uart.config == 0 || - int(uart.config) > len(configDeviceCDCACM[uart.port]) { - return statusNotSupported - } - // get platform configuration - system := configDeviceCDCACM[uart.port][uart.config-1] - - // schedule buffer for next receive event - return uart.acm.receive(system.dataBulkOutEndpoint, uart.acm.recvBuffer[:], - uint32(system.dataBulkOutPacketSize)) - } - } - } - return statusError // all non-error paths return early - - case deviceCDCACMEventSerialStateNotify: - uart.acm.hasSentState = false - return statusSuccess - - case deviceCDCACMEventSendEncapsulatedCommand: - return statusNotImplemented - - case deviceCDCACMEventGetEncapsulatedResponse: - return statusNotImplemented - - case deviceCDCACMEventSetCommFeature: - if req, ok := param.(deviceCDCACMRequestParam); ok { - switch req.setupValue { - case deviceCDCFeatureAbstractState: - if req.isSetup { - *(req.buffer) = uartAbstractState - } else { - *(req.length) = 0 - } - return statusSuccess - - case deviceCDCFeatureCountrySetting: - if req.isSetup { - *(req.buffer) = uartCountryCode - } else { - *(req.length) = 0 - } - return statusSuccess - } - return statusInvalidParameter // unrecognized request code - } - return statusError // all non-error paths return early - - case deviceCDCACMEventGetCommFeature: - if req, ok := param.(deviceCDCACMRequestParam); ok { - switch req.setupValue { - case deviceCDCFeatureAbstractState: - *(req.buffer) = uartAbstractState - *(req.length) = uint32(len(uartAbstractState)) - return statusSuccess - - case deviceCDCFeatureCountrySetting: - *(req.buffer) = uartCountryCode - *(req.length) = uint32(len(uartCountryCode)) - return statusSuccess - } - return statusInvalidParameter // unrecognized request code - } - return statusError // all non-error paths return early - - case deviceCDCACMEventClearCommFeature: - return statusNotImplemented - - case deviceCDCACMEventGetLineCoding: - if req, ok := param.(deviceCDCACMRequestParam); ok { - // verify receiver configuration - if int(uart.port) >= len(deviceCDCACMLineCoding) || uart.config == 0 || - int(uart.config) > len(deviceCDCACMLineCoding[uart.port]) { - return statusNotSupported - } - lineCoding := deviceCDCACMLineCoding[uart.port][uart.config-1] - *(req.buffer) = lineCoding - *(req.length) = uint32(len(lineCoding)) - return statusSuccess - } - return statusError // all non-error paths return early - - case deviceCDCACMEventSetLineCoding: - if req, ok := param.(deviceCDCACMRequestParam); ok { - // verify receiver configuration - if int(uart.port) >= len(deviceCDCACMLineCoding) || uart.config == 0 || - int(uart.config) > len(deviceCDCACMLineCoding[uart.port]) { - return statusNotSupported - } - lineCoding := deviceCDCACMLineCoding[uart.port][uart.config-1] - if req.isSetup { - *(req.buffer) = lineCoding - } else { - *(req.length) = uint32(len(lineCoding)) - } - return statusSuccess - } - return statusError // all non-error paths return early - - case deviceCDCACMEventSetControlLineState: - if req, ok := param.(deviceCDCACMRequestParam); ok { - // verify receiver configuration - if int(uart.port) >= len(configDeviceCDCACM) || uart.config == 0 || - int(uart.config) > len(configDeviceCDCACM[uart.port]) { - return statusNotSupported - } - // get platform configuration - system := configDeviceCDCACM[uart.port][uart.config-1] - - uart.acm.info.dteStatus = uint8(req.setupValue) - - // activate/deactivate Tx carrier - if 0 != uart.acm.info.dteStatus&deviceCDCControlSigBitmapCarrierActivation { - uart.acm.info.uartState |= deviceCDCUARTStateTxCarrier - } else { - uart.acm.info.uartState &^= deviceCDCUARTStateTxCarrier - } - - // activate/deactivate DTE and carrier - if 0 != uart.acm.info.dteStatus&deviceCDCControlSigBitmapDTEPresence { - uart.acm.info.uartState |= deviceCDCUARTStateRxCarrier - uart.acm.info.dtePresent = true // serial device is now open on host - } else { - uart.acm.info.uartState &^= deviceCDCUARTStateRxCarrier - uart.acm.info.dtePresent = false // serial device is now closed on host - } - - uart.acm.info.serialState[0] = deviceCDCACMRequestNotify // bmRequestType - uart.acm.info.serialState[1] = deviceCDCNotifySerialState // bNotification - uart.acm.info.serialState[2] = 0 // wValue (lo) - uart.acm.info.serialState[3] = 0 // wValue (hi) - uart.acm.info.serialState[4] = uint8(req.interfaceIndex) // wIndex (lo) - uart.acm.info.serialState[5] = uint8(req.interfaceIndex >> 8) // wIndex (hi) - uart.acm.info.serialState[6] = deviceCDCACMInfoUARTBitmapSize // wLength (lo) - uart.acm.info.serialState[7] = 0 // wLength (hi) - uart.acm.info.serialState[8] = uint8(uart.acm.info.uartState) // UART bitmap (lo) - uart.acm.info.serialState[9] = uint8(uart.acm.info.uartState >> 8) // UART bitmap (hi) - - s := statusSuccess - if !uart.acm.hasSentState { - s = uart.acm.send(system.commInterruptInEndpoint, - uart.acm.info.serialState[:], deviceCDCACMSerialStateSize) - uart.acm.hasSentState = true - } - - // update status - if 0 != uart.acm.info.dteStatus&deviceCDCControlSigBitmapCarrierActivation { - // carrier activated - } - if 0 != uart.acm.info.dteStatus&deviceCDCControlSigBitmapDTEPresence { - // DTE activated - if uart.attached { - uart.transact = true - } - } else { - // DTE deactivated - if uart.attached { - uart.transact = false - } - } - - return s - } - return statusError // all non-error paths return early - - case deviceCDCACMEventSendBreak: - return statusNotImplemented - - default: - return statusInvalidParameter + n, ok := 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) { + dc, ok := uart.core.dc.(*deviceController) + if !ok { + return 0, ErrUARTInvalidCore + } + return dc.uartRead(data), nil +} + +// WriteByte writes a single byte of data to the UART interface. +func (uart UART) WriteByte(c byte) error { + dc, ok := uart.core.dc.(*deviceController) + if !ok { + return ErrUARTInvalidCore + } + if !dc.uartWriteByte(c) { + return ErrUARTWriteFailed + } + return nil +} + +// Write data to the UART. +func (uart UART) Write(data []byte) (n int, err error) { + dc, ok := uart.core.dc.(*deviceController) + if !ok { + return 0, ErrUARTInvalidCore + } + return dc.uartWrite(data), nil } diff --git a/src/machine/usb/usb.go b/src/machine/usb/usb.go index 888d2cfcd..4f3d4e2cf 100644 --- a/src/machine/usb/usb.go +++ b/src/machine/usb/usb.go @@ -1,416 +1,157 @@ package usb -type ( - // status is the common error code used internally for package operations. - status int8 - // mode defines the operating mode of a USB port. - mode int8 +// Hardware abstraction for USB ports configured as either host or device. - // port represents a physical USB port, which may be configured as either a - // device or as a host. - port struct { - mode mode - device device - host host - } -) - -// Constants for unexported types shared across entire package. -const ( - statusSuccess status = iota // Success - statusError // Failed - statusBusy // Busy - statusInvalidHandle // Invalid handle - statusInvalidParameter // Invalid parameter - statusInvalidRequest // Invalid request - statusControllerNotFound // Controller cannot be found - statusInvalidController // Invalid controller interface - statusNotSupported // Configuration is not supported - statusRetry // Enumeration get configuration retry - statusTransferStall // Transfer stalled - statusTransferFailed // Transfer failed - statusAllocFail // Allocation failed - statusLackSwapBuffer // Insufficient swap buffer for KHCI - statusTransferCancel // The transfer cancelled - statusBandwidthFail // Allocate bandwidth failed - statusMSDStatusFail // For MSD, the CSW status means fail - statusEHCIAttached // EHCI attached - statusEHCIDetached // EHCI detached - statusDataOverRun // Endpoint data (Rx) exceeds max size - statusNotImplemented // Supported feature not implemented - - modeIdle mode = iota // USB core idle (unallocated) - modeDevice // USB device mode - modeHost // USB host mode -) - -var ( - // portInstance holds instances for all available ports on the platform. - portInstance [ConfigPortCount]port -) +import "unsafe" func init() { - // ensure all ports are in idle state by default - for i := range portInstance { - portInstance[i].mode = modeIdle + if unsafe.Sizeof(uintptr(0)) > 4 { + panic("USB is only supported on 32-bit systems") } } -func ProcessMessages() (err error) { - for i := range portInstance { - s := portInstance[i].process() - if !s.OK() && nil == err { - err = s +// core represents the core of a USB port configured as either host or device. +type core struct { + port int + mode int + dc dcd + hc hcd +} + +// Constant definitions for USB core operating modes. +const ( + modeIdle = 0 + modeDevice = 1 + modeHost = 2 +) + +// class represents the type of a host/device and its class configuration index. +// The first valid configuration index is 1. Index 0 is reserved and invalid. +type class struct { + id int + config int +} + +// Constant definitions for all host/device classes. +const ( + classDeviceCDCACM = 0 // The only currently-supported class (CDC-ACM) +) + +// mode returns the USB core operating mode of the receiver class cl. +//go:inline +func (cl class) mode() int { + switch cl.id { + case classDeviceCDCACM: + return modeDevice + default: + return modeIdle + } +} + +// equals returns true if and only if all fields of the given class are equal to +// those of the receiver cl. +//go:inline +func (cl class) equals(class class) bool { + return cl.id == class.id && cl.config == class.config +} + +// CoreCount defines the total number of USB cores to configure in device or +// host mode. +const CoreCount = dcdCount + hcdCount + +// coreInstance provides statically-allocated instances of each USB core +// configured on this platform. +var coreInstance [CoreCount]core + +// status represents the return code of a subroutine. +type status uint8 + +// Constant definitions for all status codes used within the package. +const ( + statusOK status = iota // Success + statusBusy // Busy + statusRetry // Retry + statusInvalid // Invalid argument +) + +// ok returns true if and only if the receiver st equals statusOK. +//go:inline +func (st status) ok() bool { return statusOK == st } + +// initCore initializes a free USB core with given operating mode on the USB +// port at given index, if available. Returns a reference to the initialized +// core or nil if the core is unavailable. +func initCore(port int, class class) (*core, status) { + + if port < 0 || port >= CoreCount || 0 == class.config { + return nil, statusInvalid + } + + if modeIdle != coreInstance[port].mode { + // Check if requested port is already configured as requested class. If so, + // just return a reference to the existing core instead of an error. + // For instance, this will allow TinyGo examples that try to reconfigure the + // USB (CDC-ACM) UART port (which is already configured by the runtime) to + // continue without error. + if coreInstance[port].mode == class.mode() { + switch class.mode() { + case modeDevice: + if coreInstance[port].dc.class().equals(class) { + return &coreInstance[port], statusOK + } + case modeHost: + if coreInstance[port].hc.class().equals(class) { + return &coreInstance[port], statusOK + } + } } - } - return -} - -// initPort configures the mode for a given USB port and initializes the -// hardware's port controller. If the port is invalid or not idle (it has -// already been configured), it returns nil and a status code. -func initPort(port uint8, mode mode) (*port, status) { - if port >= ConfigPortCount || int(port) >= len(portInstance) { - return nil, statusInvalidController - } - if modeIdle != portInstance[port].mode { return nil, statusBusy } - portInstance[port].mode = mode - switch mode { + + switch class.mode() { case modeDevice: - if s := portInstance[port].device.init(port); !s.OK() { - return nil, s + // Allocate a free device controller and install interrupts + dc, st := initDCD(port, class) + if !st.ok() { + return nil, st } - case modeHost: - if s := portInstance[port].host.init(port); !s.OK() { - return nil, s + // Initialize buffers and device descriptors + if st = dc.init(); !st.ok() { + return nil, st + } + coreInstance[port].port = port + coreInstance[port].mode = modeDevice + coreInstance[port].dc = dc + // Enable interrupts and enter runtime + if st = dc.enable(true); !st.ok() { + coreInstance[port].mode = modeIdle + coreInstance[port].dc = nil + return nil, st } - } - return &portInstance[port], statusSuccess -} -// deinit disables the receiver USB port, changing its mode to idle, freeing it -// for reuse or reconfiguration. -func (p *port) deinit() status { - switch p.mode { - case modeDevice: - return p.device.deinit() case modeHost: - return p.host.deinit() + // Allocate a free host controller and install interrupts + hc, st := initHCD(port, class) + if !st.ok() { + return nil, st + } + // Initialize buffers and device descriptors + if st = hc.init(); !st.ok() { + return nil, st + } + coreInstance[port].port = port + coreInstance[port].mode = modeHost + coreInstance[port].hc = hc + // Enable interrupts and enter runtime + if st = hc.enable(true); !st.ok() { + coreInstance[port].mode = modeIdle + coreInstance[port].hc = nil + return nil, st + } + default: - return statusInvalidController + return nil, statusInvalid } -} - -func (p *port) process() status { - switch p.mode { - case modeDevice: - return p.device.controller.process() - case modeHost: - return statusSuccess // TODO: not implemented - default: - return statusInvalidController - } -} - -// initCDCACM applies a CDC-ACM configuration to the receiver port p and then -// returns the configured deviceClassDriver and deviceClass that were assigned -// to the receiver. -// -// The given deviceClassEventHandler is called for any USB device-level event -// notifications received, which allows an upper-layer CDC-ACM driver (such as -// a UART interface implementation) the opportunity to handle device events. -func (p *port) initCDCACM(id uint8, handler deviceClassEventHandler) (*deviceCDCACM, *deviceClass) { - - // verify a valid port was provided - if nil == p || nil == p.device.controller || p.mode != modeDevice { - return nil, nil - } - - if 0 == id || int(id) > len(configDeviceCDCACM[p.device.port]) { - return nil, nil - } - - // get a reference to each of the class interfaces - comm := &deviceCDCACMConfigInstance[p.device.port][id-1].info.interfaceList[0] - data := &deviceCDCACMConfigInstance[p.device.port][id-1].info.interfaceList[1] - - // configDeviceCDCACM must be defined per package API. these settings will be - // platform-specific, and will probably be implemented in a build tag- - // constrained source file. the length of this array corresponds to the number - // of USB CDC-ACM ports that are being created, and the index of each element - // corresponds to the physical USB port (core index). Each element is a slice - // of alternate device configurations that may be selected for a given port. - - // CDC-ACM Communication/control interface - comm.interfaceNumber = - configDeviceCDCACM[p.device.port][id-1].commInterfaceIndex - - comm.deviceInterface[0].endpoint[0].address = - configDeviceCDCACM[p.device.port][id-1].commInterruptInEndpoint | - specDescriptorEndpointAddressDirectionIn - - comm.deviceInterface[0].endpoint[0].maxPacketSize = - configDeviceCDCACM[p.device.port][id-1].commInterruptInPacketSize - - comm.deviceInterface[0].endpoint[0].interval = - configDeviceCDCACM[p.device.port][id-1].commInterruptInInterval - - // CDC-ACM Data interface - data.interfaceNumber = - configDeviceCDCACM[p.device.port][id-1].dataInterfaceIndex - - data.deviceInterface[0].endpoint[0].address = - configDeviceCDCACM[p.device.port][id-1].dataBulkInEndpoint | - specDescriptorEndpointAddressDirectionIn - - data.deviceInterface[0].endpoint[0].maxPacketSize = - configDeviceCDCACM[p.device.port][id-1].dataBulkInPacketSize - - data.deviceInterface[0].endpoint[1].address = - configDeviceCDCACM[p.device.port][id-1].dataBulkOutEndpoint | - specDescriptorEndpointAddressDirectionOut - - data.deviceInterface[0].endpoint[1].maxPacketSize = - configDeviceCDCACM[p.device.port][id-1].dataBulkOutPacketSize - - // assign our configured CDC-ACM class to the receiver's device and call its - // class initialization routine(s). - cls := p.device.initClass(id, deviceCDCACMConfigInstance[p.device.port], handler) - acm := cls.config[0].driver.(*deviceCDCACM) - - return acm, cls -} - -// OK returns true if and only if the receiver s is equal to statusSuccess. -//go:inline -func (s status) OK() bool { return statusSuccess == s } - -// Error returns a simple descriptive error string of the receiver s. -func (s status) Error() string { - switch s { - case statusSuccess: - return "" - case statusError: - return "failed" - case statusBusy: - return "busy" - case statusInvalidHandle: - return "invalid handle" - case statusInvalidParameter: - return "invalid parameter" - case statusInvalidRequest: - return "invalid request" - case statusControllerNotFound: - return "controller not found" - case statusInvalidController: - return "invalid controller interface" - case statusNotSupported: - return "configuration not supported" - case statusRetry: - return "retry enumeration" - case statusTransferStall: - return "transfer stalled" - case statusTransferFailed: - return "transfer failed" - case statusAllocFail: - return "allocation failed" - case statusLackSwapBuffer: - return "insufficient swap buffer" - case statusTransferCancel: - return "transfer cancelled" - case statusBandwidthFail: - return "bandwidth allocation failed" - case statusMSDStatusFail: - return "mass-storage device failed" - case statusEHCIAttached: - return "host attached" - case statusEHCIDetached: - return "host detached" - case statusDataOverRun: - return "data overrun" - case statusNotImplemented: - return "feature not implemented" - default: - return "unknown error" - } -} - -// leU64 returns a slice containing 8 bytes from the given uint64 u. -// -// The returned bytes have little-endian ordering; that is, the first element -// at index 0 is the least-significant byte in u and index 7 is the most- -// significant byte. -//go:inline -func leU64(u uint64) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0, 0, 0, 0, 0, 0, 0} - } - return []uint8{ - uint8(u), uint8(u >> 8), uint8(u >> 16), uint8(u >> 24), - uint8(u >> 32), uint8(u >> 40), uint8(u >> 48), uint8(u >> 56), - } -} - -// leU32 returns a slice containing 4 bytes from the given uint32 u. -// -// The returned bytes have little-endian ordering; that is, the first element -// at index 0 is the least-significant byte in u and index 3 is the most- -// significant byte. -//go:inline -func leU32(u uint32) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0, 0, 0} - } - return []uint8{ - uint8(u), uint8(u >> 8), uint8(u >> 16), uint8(u >> 24), - } -} - -// leU16 returns a slice containing 2 bytes from the given uint16 u. -// -// The returned bytes have little-endian ordering; that is, the first element -// at index 0 is the least-significant byte in u and index 1 is the most- -// significant byte. -//go:inline -func leU16(u uint16) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0} - } - return []uint8{ - uint8(u), uint8(u >> 8), - } -} - -// beU64 returns a slice containing 8 bytes from the given uint64 u. -// -// The returned bytes have big-endian ordering; that is, the first element at -// index 0 is the most-significant byte in u and index 7 is the least- -// significant byte. -//go:inline -func beU64(u uint64) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0, 0, 0, 0, 0, 0, 0} - } - return []uint8{ - uint8(u >> 56), uint8(u >> 48), uint8(u >> 40), uint8(u >> 32), - uint8(u >> 24), uint8(u >> 16), uint8(u >> 8), uint8(u), - } -} - -// beU32 returns a slice containing 4 bytes from the given uint32 u. -// -// The returned bytes have big-endian ordering; that is, the first element at -// index 0 is the most-significant byte in u and index 3 is the least- -// significant byte. -//go:inline -func beU32(u uint32) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0, 0, 0} - } - return []uint8{ - uint8(u >> 24), uint8(u >> 16), uint8(u >> 8), uint8(u), - } -} - -// beU16 returns a slice containing 2 bytes from the given uint16 u. -// -// The returned bytes have big-endian ordering; that is, the first element at -// index 0 is the most-significant byte in u and index 1 is the least- -// significant byte. -//go:inline -func beU16(u uint16) []uint8 { - if u == 0 { - // skip all processing for the common case (u = 0) - return []uint8{0, 0} - } - return []uint8{ - uint8(u >> 8), uint8(u), - } -} - -// revU64 returns the given uint64 u with bytes in the reverse order. -//go:inline -func revU64(u uint64) uint64 { - if u == 0 { - // skip all processing for the common case (u = 0) - return 0 - } - return ((u & 0x00000000000000FF) << 56) | - ((u & 0x000000000000FF00) << 40) | - ((u & 0x0000000000FF0000) << 24) | - ((u & 0x00000000FF000000) << 8) | - ((u & 0x000000FF00000000) >> 8) | - ((u & 0x0000FF0000000000) >> 24) | - ((u & 0x00FF000000000000) >> 40) | - ((u & 0xFF00000000000000) >> 56) -} - -// revU32 returns the given uint32 u with bytes in the reverse order. -//go:inline -func revU32(u uint32) uint32 { - if u == 0 { - // skip all processing for the common case (u = 0) - return 0 - } - return ((u & 0x000000FF) << 24) | ((u & 0x0000FF00) << 8) | - ((u & 0x00FF0000) >> 8) | ((u & 0xFF000000) >> 24) -} - -// revU16 returns the given uint16 u with bytes in the reverse order. -//go:inline -func revU16(u uint16) uint16 { - if u == 0 { - // skip all processing for the common case (u = 0) - return 0 - } - return ((u & 0x00FF) << 8) | ((u & 0xFF00) >> 8) -} - -// packU64 returns a uint64 constructed by concatenating the bytes in slice b. -// -// The least-significant byte in the returned value is the first element at -// index 0 in b and the most significant byte is index 7, if given. If fewer -// than 8 elements are given in b, the corresponding bytes in the returned value -// are all 0. -//go:inline -func packU64(b []uint8) (u uint64) { - for i := 0; i < 8 && i < len(b); i++ { - u |= uint64(b[i]) << (i * 8) - } - return -} - -// packU32 returns a uint32 constructed by concatenating the bytes in slice b. -// -// The least-significant byte in the returned value is the first element at -// index 0 in b and the most significant byte is index 3, if given. If fewer -// than 4 elements are given in b, the corresponding bytes in the returned value -// are all 0. -//go:inline -func packU32(b []uint8) (u uint32) { - for i := 0; i < 4 && i < len(b); i++ { - u |= uint32(b[i]) << (i * 8) - } - return -} - -// packU16 returns a uint16 constructed by concatenating the bytes in slice b. -// -// The least-significant byte in the returned value is the first element at -// index 0 in b and the most significant byte is index 1, if given. If fewer -// than 2 elements are given in b, the corresponding bytes in the returned value -// are all 0. -//go:inline -func packU16(b []uint8) (u uint16) { - for i := 0; i < 2 && i < len(b); i++ { - u |= uint16(b[i]) << (i * 8) - } - return + + return &coreInstance[port], statusOK } diff --git a/src/machine/usb2/util.go b/src/machine/usb/util.go similarity index 99% rename from src/machine/usb2/util.go rename to src/machine/usb/util.go index 35a082a7a..94dfff99d 100644 --- a/src/machine/usb2/util.go +++ b/src/machine/usb/util.go @@ -1,4 +1,4 @@ -package usb2 +package usb // leU64 returns a slice containing 8 bytes from the given uint64 u. // diff --git a/src/machine/usb2/util_arm.go b/src/machine/usb/util_arm.go similarity index 96% rename from src/machine/usb2/util_arm.go rename to src/machine/usb/util_arm.go index 8f7b8a2a9..89ab4f646 100644 --- a/src/machine/usb2/util_arm.go +++ b/src/machine/usb/util_arm.go @@ -1,6 +1,6 @@ // +build arm -package usb2 +package usb import "device/arm" diff --git a/src/machine/usb2/uart.go b/src/machine/usb2/uart.go deleted file mode 100644 index a5e32ff0e..000000000 --- a/src/machine/usb2/uart.go +++ /dev/null @@ -1,93 +0,0 @@ -package usb2 - -import ( - "errors" -) - -var ( - ErrUARTInvalidPort = errors.New("invalid USB port") - ErrUARTInvalidCore = errors.New("invalid USB core") - ErrUARTEmptyBuffer = errors.New("USB receive buffer empty") - ErrUARTWriteFailed = errors.New("USB write failure") -) - -type ( - UARTConfig struct { - BaudRate uint32 - } - - // UART represents a virtual serial (UART) device emulation using the USB - // CDC-ACM device class driver. - UART struct { - port int // USB port (core index, e.g., 0-1) - core *core - } -) - -func (uart *UART) Configure(config UARTConfig) error { - - if uart.port >= CoreCount || uart.port >= dcdCount { - return ErrUARTInvalidPort - } - - // verify we have a free USB port and take ownership of it - var st status - uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1}) - if !st.ok() { - return ErrUARTInvalidPort - } - return nil -} - -// Buffered returns the number of bytes currently stored in the RX buffer. -func (uart UART) Buffered() int { - dc, ok := uart.core.dc.(*deviceController) - if !ok { - return 0 - } - return 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) { - dc, ok := uart.core.dc.(*deviceController) - if !ok { - return 0, ErrUARTInvalidCore - } - n, ok := 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) { - dc, ok := uart.core.dc.(*deviceController) - if !ok { - return 0, ErrUARTInvalidCore - } - return dc.uartRead(data), nil -} - -// WriteByte writes a single byte of data to the UART interface. -func (uart UART) WriteByte(c byte) error { - dc, ok := uart.core.dc.(*deviceController) - if !ok { - return ErrUARTInvalidCore - } - if !dc.uartWriteByte(c) { - return ErrUARTWriteFailed - } - return nil -} - -// Write data to the UART. -func (uart UART) Write(data []byte) (n int, err error) { - dc, ok := uart.core.dc.(*deviceController) - if !ok { - return 0, ErrUARTInvalidCore - } - return dc.uartWrite(data), nil -} diff --git a/src/machine/usb2/usb.go b/src/machine/usb2/usb.go deleted file mode 100644 index e78bdbd04..000000000 --- a/src/machine/usb2/usb.go +++ /dev/null @@ -1,157 +0,0 @@ -package usb2 - -// Hardware abstraction for USB ports configured as either host or device. - -import "unsafe" - -func init() { - if unsafe.Sizeof(uintptr(0)) > 4 { - panic("USB is only supported on 32-bit systems") - } -} - -// core represents the core of a USB port configured as either host or device. -type core struct { - port int - mode int - dc dcd - hc hcd -} - -// Constant definitions for USB core operating modes. -const ( - modeIdle = 0 - modeDevice = 1 - modeHost = 2 -) - -// class represents the type of a host/device and its class configuration index. -// The first valid configuration index is 1. Index 0 is reserved and invalid. -type class struct { - id int - config int -} - -// Constant definitions for all host/device classes. -const ( - classDeviceCDCACM = 0 // The only currently-supported class (CDC-ACM) -) - -// mode returns the USB core operating mode of the receiver class cl. -//go:inline -func (cl class) mode() int { - switch cl.id { - case classDeviceCDCACM: - return modeDevice - default: - return modeIdle - } -} - -// equals returns true if and only if all fields of the given class are equal to -// those of the receiver cl. -//go:inline -func (cl class) equals(class class) bool { - return cl.id == class.id && cl.config == class.config -} - -// CoreCount defines the total number of USB cores to configure in device or -// host mode. -const CoreCount = dcdCount + hcdCount - -// coreInstance provides statically-allocated instances of each USB core -// configured on this platform. -var coreInstance [CoreCount]core - -// status represents the return code of a subroutine. -type status uint8 - -// Constant definitions for all status codes used within the package. -const ( - statusOK status = iota // Success - statusBusy // Busy - statusRetry // Retry - statusInvalid // Invalid argument -) - -// ok returns true if and only if the receiver st equals statusOK. -//go:inline -func (st status) ok() bool { return statusOK == st } - -// initCore initializes a free USB core with given operating mode on the USB -// port at given index, if available. Returns a reference to the initialized -// core or nil if the core is unavailable. -func initCore(port int, class class) (*core, status) { - - if port < 0 || port >= CoreCount || 0 == class.config { - return nil, statusInvalid - } - - if modeIdle != coreInstance[port].mode { - // Check if requested port is already configured as requested class. If so, - // just return a reference to the existing core instead of an error. - // For instance, this will allow TinyGo examples that try to reconfigure the - // USB (CDC-ACM) UART port (which is already configured by the runtime) to - // continue without error. - if coreInstance[port].mode == class.mode() { - switch class.mode() { - case modeDevice: - if coreInstance[port].dc.class().equals(class) { - return &coreInstance[port], statusOK - } - case modeHost: - if coreInstance[port].hc.class().equals(class) { - return &coreInstance[port], statusOK - } - } - } - return nil, statusBusy - } - - switch class.mode() { - case modeDevice: - // Allocate a free device controller and install interrupts - dc, st := initDCD(port, class) - if !st.ok() { - return nil, st - } - // Initialize buffers and device descriptors - if st = dc.init(); !st.ok() { - return nil, st - } - coreInstance[port].port = port - coreInstance[port].mode = modeDevice - coreInstance[port].dc = dc - // Enable interrupts and enter runtime - if st = dc.enable(true); !st.ok() { - coreInstance[port].mode = modeIdle - coreInstance[port].dc = nil - return nil, st - } - - case modeHost: - // Allocate a free host controller and install interrupts - hc, st := initHCD(port, class) - if !st.ok() { - return nil, st - } - // Initialize buffers and device descriptors - if st = hc.init(); !st.ok() { - return nil, st - } - coreInstance[port].port = port - coreInstance[port].mode = modeHost - coreInstance[port].hc = hc - // Enable interrupts and enter runtime - if st = hc.enable(true); !st.ok() { - coreInstance[port].mode = modeIdle - coreInstance[port].hc = nil - return nil, st - } - - default: - return nil, statusInvalid - } - - return &coreInstance[port], statusOK -}