diff options
Diffstat (limited to 'src/machine/usb.go')
-rw-r--r-- | src/machine/usb.go | 188 |
1 files changed, 65 insertions, 123 deletions
diff --git a/src/machine/usb.go b/src/machine/usb.go index ebdacfdaf..3656edc7b 100644 --- a/src/machine/usb.go +++ b/src/machine/usb.go @@ -14,25 +14,25 @@ type USBDevice struct { var ( USBDev = &USBDevice{} + USBCDC Serialer ) + +type Serialer interface { + WriteByte(c byte) error + Write(data []byte) (n int, err error) + Configure(config UARTConfig) error + Buffered() int + ReadByte() (byte, error) +} + var usbDescriptor = descriptorCDC -var ( - errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty") - errUSBCDCWriteByteTimeout = errors.New("USB-CDC write byte timeout") - errUSBCDCReadTimeout = errors.New("USB-CDC read timeout") - errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read") +const ( + usbDescriptorConfigCDC = 1 << iota + usbDescriptorConfigHID ) -const cdcLineInfoSize = 7 - -type cdcLineInfo struct { - dwDTERate uint32 - bCharFormat uint8 - bParityType uint8 - bDataBits uint8 - lineState uint8 -} +var usbDescriptorConfig uint8 = usbDescriptorConfigCDC // strToUTF16LEDescriptor converts a utf8 string into a string descriptor // note: the following code only converts ascii characters to UTF16LE. In order @@ -54,22 +54,25 @@ var ( usb_STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English ) +const cdcLineInfoSize = 7 + +var ( + ErrUSBReadTimeout = errors.New("USB read timeout") + ErrUSBBytesRead = errors.New("USB invalid number of bytes read") +) + var ( - usbEndpointDescriptors [8]usbDeviceDescriptor + usbEndpointDescriptors [numberOfEndpoints]usbDeviceDescriptor - udd_ep_in_cache_buffer [7][128]uint8 - udd_ep_out_cache_buffer [7][128]uint8 + udd_ep_control_cache_buffer [256]uint8 + udd_ep_in_cache_buffer [7][64]uint8 + udd_ep_out_cache_buffer [7][64]uint8 isEndpointHalt = false isRemoteWakeUpEnabled = false - endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL, - (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn), - (usb_ENDPOINT_TYPE_BULK | usbEndpointOut), - (usb_ENDPOINT_TYPE_BULK | usbEndpointIn)} usbConfiguration uint8 usbSetInterface uint8 - usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00} ) const ( @@ -77,6 +80,7 @@ const ( usb_IPRODUCT = 2 usb_ISERIAL = 3 + usb_ENDPOINT_TYPE_DISABLE = 0xFF usb_ENDPOINT_TYPE_CONTROL = 0x00 usb_ENDPOINT_TYPE_ISOCHRONOUS = 0x01 usb_ENDPOINT_TYPE_BULK = 0x02 @@ -95,8 +99,8 @@ const ( usbEndpointOut = 0x00 usbEndpointIn = 0x80 + numberOfEndpoints = 8 usbEndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024 - usb_EPT_NUM = 7 // standard requests usb_GET_STATUS = 0 @@ -123,12 +127,15 @@ const ( usb_CONFIG_SELF_POWERED = 0xC0 usb_CONFIG_REMOTE_WAKEUP = 0x20 - // CDC + // Interface + numberOfInterfaces = 3 usb_CDC_ACM_INTERFACE = 0 // CDC ACM usb_CDC_DATA_INTERFACE = 1 // CDC Data usb_CDC_FIRST_ENDPOINT = 1 + usb_HID_INTERFACE = 2 // HID // Endpoint + usb_CONTROL_ENDPOINT = 0 usb_CDC_ENDPOINT_ACM = 1 usb_CDC_ENDPOINT_OUT = 2 usb_CDC_ENDPOINT_IN = 3 @@ -153,27 +160,20 @@ const ( usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE) usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE) usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE) +) - // CDC Class requests - usb_CDC_SET_LINE_CODING = 0x20 - usb_CDC_GET_LINE_CODING = 0x21 - usb_CDC_SET_CONTROL_LINE_STATE = 0x22 - usb_CDC_SEND_BREAK = 0x23 - - usb_CDC_V1_10 = 0x0110 - usb_CDC_COMMUNICATION_INTERFACE_CLASS = 0x02 - - usb_CDC_CALL_MANAGEMENT = 0x01 - usb_CDC_ABSTRACT_CONTROL_MODEL = 0x02 - usb_CDC_HEADER = 0x00 - usb_CDC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 - usb_CDC_UNION = 0x06 - usb_CDC_CS_INTERFACE = 0x24 - usb_CDC_CS_ENDPOINT = 0x25 - usb_CDC_DATA_INTERFACE_CLASS = 0x0A - - usb_CDC_LINESTATE_DTR = 0x01 - usb_CDC_LINESTATE_RTS = 0x02 +var ( + usbTxHandler [numberOfEndpoints]func() + usbRxHandler [numberOfEndpoints]func([]byte) + usbSetupHandler [numberOfInterfaces]func(USBSetup) bool + + endPoints = []uint32{ + usb_CONTROL_ENDPOINT: usb_ENDPOINT_TYPE_CONTROL, + usb_CDC_ENDPOINT_ACM: (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn), + usb_CDC_ENDPOINT_OUT: (usb_ENDPOINT_TYPE_BULK | usbEndpointOut), + usb_CDC_ENDPOINT_IN: (usb_ENDPOINT_TYPE_BULK | usbEndpointIn), + usb_HID_ENDPOINT_IN: (usb_ENDPOINT_TYPE_DISABLE), // Interrupt In + } ) // usbDeviceDescBank is the USB device endpoint descriptor. @@ -209,73 +209,6 @@ func newUSBSetup(data []byte) USBSetup { return u } -// USBCDC is the serial interface that works over the USB port. -// To implement the USBCDC interface for a board, you must declare a concrete type as follows: -// -// type USBCDC struct { -// Buffer *RingBuffer -// } -// -// You can also add additional members to this struct depending on your implementation, -// but the *RingBuffer is required. -// When you are declaring the USBCDC for your board, make sure that you also declare the -// RingBuffer using the NewRingBuffer() function: -// -// USBCDC{Buffer: NewRingBuffer()} -// - -// Read from the RX buffer. -func (usbcdc *USBCDC) Read(data []byte) (n int, err error) { - // check if RX buffer is empty - size := usbcdc.Buffered() - if size == 0 { - return 0, nil - } - - // Make sure we do not read more from buffer than the data slice can hold. - if len(data) < size { - size = len(data) - } - - // only read number of bytes used from buffer - for i := 0; i < size; i++ { - v, _ := usbcdc.ReadByte() - data[i] = v - } - - return size, nil -} - -// Write data to the USBCDC. -func (usbcdc *USBCDC) Write(data []byte) (n int, err error) { - for _, v := range data { - usbcdc.WriteByte(v) - } - return len(data), nil -} - -// ReadByte reads a single byte from the RX buffer. -// If there is no data in the buffer, returns an error. -func (usbcdc *USBCDC) ReadByte() (byte, error) { - // check if RX buffer is empty - buf, ok := usbcdc.Buffer.Get() - if !ok { - return 0, errUSBCDCBufferEmpty - } - return buf, nil -} - -// Buffered returns the number of bytes currently stored in the RX buffer. -func (usbcdc *USBCDC) Buffered() int { - return int(usbcdc.Buffer.Used()) -} - -// Receive handles adding data to the UART's data buffer. -// Usually called by the IRQ handler for a machine. -func (usbcdc *USBCDC) Receive(data byte) { - usbcdc.Buffer.Put(data) -} - // sendDescriptor creates and sends the various USB descriptor types that // can be requested by the host. func sendDescriptor(setup USBSetup) { @@ -285,6 +218,11 @@ func sendDescriptor(setup USBSetup) { return case usb_DEVICE_DESCRIPTOR_TYPE: // composite descriptor + if (usbDescriptorConfig & usbDescriptorConfigHID) > 0 { + usbDescriptor = descriptorCDCHID + } else { + usbDescriptor = descriptorCDC + } usbDescriptor.Configure(usb_VID, usb_PID) sendUSBPacket(0, usbDescriptor.Device, setup.WLength) return @@ -402,17 +340,21 @@ func handleStandardSetup(setup USBSetup) bool { } } -// EnableHID enables HID. This function must be executed from the init(). -func EnableHID(callback func()) { - usbDescriptor = descriptorCDCHID - endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL, - (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn), - (usb_ENDPOINT_TYPE_BULK | usbEndpointOut), - (usb_ENDPOINT_TYPE_BULK | usbEndpointIn), - (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)} - - hidCallback = callback +func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) { + usbDescriptorConfig |= usbDescriptorConfigCDC + endPoints[usb_CDC_ENDPOINT_ACM] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn) + endPoints[usb_CDC_ENDPOINT_OUT] = (usb_ENDPOINT_TYPE_BULK | usbEndpointOut) + endPoints[usb_CDC_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_BULK | usbEndpointIn) + usbRxHandler[usb_CDC_ENDPOINT_OUT] = rxHandler + usbTxHandler[usb_CDC_ENDPOINT_IN] = txHandler + usbSetupHandler[usb_CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control) + usbSetupHandler[usb_CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data) } -// hidCallback is a variable that holds the callback when using HID. -var hidCallback func() +// EnableHID enables HID. This function must be executed from the init(). +func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) { + usbDescriptorConfig |= usbDescriptorConfigHID + endPoints[usb_HID_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn) + usbTxHandler[usb_HID_ENDPOINT_IN] = txHandler + usbSetupHandler[usb_HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device) +} |