machine/atsamd21: support for USB CDC aka serial interface

Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
Ron Evans 2019-02-21 20:29:12 +01:00 коммит произвёл Ayke van Laethem
родитель 7f027ddd33
коммит 5438f16fcb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
4 изменённых файлов: 1545 добавлений и 11 удалений

Просмотреть файл

@ -34,7 +34,13 @@ const (
LED = D13
)
// UART0 pins
// UART0 aka USBCDC pins
const (
USBCDC_DM_PIN = 24
USBCDC_DP_PIN = 25
)
// UART1 pins
const (
UART_TX_PIN = D1
UART_RX_PIN = D0

Просмотреть файл

@ -8,9 +8,12 @@
package machine
import (
"bytes"
"device/arm"
"device/sam"
"encoding/binary"
"errors"
"unsafe"
)
const CPU_FREQUENCY = 48000000
@ -57,6 +60,19 @@ func (p GPIO) Configure(config GPIOConfig) {
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
case GPIO_COM:
if p.Pin&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (GPIO_COM << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (GPIO_COM << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
}
}
@ -102,11 +118,14 @@ type UART struct {
}
var (
// UART0 is actually a USB CDC interface.
UART0 = USBCDC{Buffer: NewRingBuffer()}
// The first hardware serial port on the SAMD21. Uses the SERCOM0 interface.
UART0 = UART{Bus: sam.SERCOM0_USART, Buffer: NewRingBuffer()}
UART1 = UART{Bus: sam.SERCOM0_USART, Buffer: NewRingBuffer()}
// The second hardware serial port on the SAMD21. Uses the SERCOM1 interface.
UART1 = UART{Bus: sam.SERCOM1_USART, Buffer: NewRingBuffer()}
UART2 = UART{Bus: sam.SERCOM1_USART, Buffer: NewRingBuffer()}
)
const (
@ -249,19 +268,19 @@ func (uart UART) WriteByte(c byte) error {
}
//go:export SERCOM0_IRQHandler
func handleUART0() {
// should reset IRQ
UART0.Receive(byte((UART0.Bus.DATA & 0xFF)))
UART0.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC
}
//go:export SERCOM1_IRQHandler
func handleUART1() {
// should reset IRQ
UART1.Receive(byte((UART1.Bus.DATA & 0xFF)))
UART1.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC
}
//go:export SERCOM1_IRQHandler
func handleUART2() {
// should reset IRQ
UART2.Receive(byte((UART2.Bus.DATA & 0xFF)))
UART2.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC
}
// I2C on the SAMD21.
type I2C struct {
Bus *sam.SERCOM_I2CM_Type
@ -906,3 +925,901 @@ func (pwm PWM) setChannel(val sam.RegValue) {
return // not supported on this pin
}
}
// USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
type USBCDC struct {
Buffer *RingBuffer
}
// WriteByte writes a byte of data to the USB CDC interface.
func (usbcdc USBCDC) WriteByte(c byte) error {
// Supposedly to handle problem with Windows USB serial ports?
if usbLineInfo.lineState > 0 {
// set the data
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][0] = c
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN])))
// clean multi packet size of bytes already sent
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE &^=
sam.RegValue(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set count of bytes to be sent
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE |=
sam.RegValue((1&usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)<<usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) |
sam.RegValue(epPacketSize(64)<<usb_DEVICE_PCKSIZE_SIZE_Pos)
// ack transfer complete flag
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
// send data by setting bank ready
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
// wait for transfer to complete
for (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) == 0 {
}
}
return nil
}
const (
// these are SAMD21 specific.
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0
usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF
usb_DEVICE_PCKSIZE_SIZE_Pos = 28
usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14
usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF
)
var (
usbEndpointDescriptors [8]usbDeviceDescriptor
udd_ep_in_cache_buffer [7][128]uint8
udd_ep_out_cache_buffer [7][128]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}
)
// Configure the USB CDC interface. The config is here for compatibility with the UART interface.
func (usbcdc USBCDC) Configure(config UARTConfig) {
// reset USB interface
sam.USB_DEVICE.CTRLA |= sam.USB_DEVICE_CTRLA_SWRST
for (sam.USB_DEVICE.SYNCBUSY&sam.USB_DEVICE_SYNCBUSY_SWRST) > 0 ||
(sam.USB_DEVICE.SYNCBUSY&sam.USB_DEVICE_SYNCBUSY_ENABLE) > 0 {
}
sam.USB_DEVICE.DESCADD = sam.RegValue(uintptr(unsafe.Pointer(&usbEndpointDescriptors)))
// configure pins
GPIO{USBCDC_DM_PIN}.Configure(GPIOConfig{Mode: GPIO_COM})
GPIO{USBCDC_DP_PIN}.Configure(GPIOConfig{Mode: GPIO_COM})
// performs pad calibration from store fuses
handlePadCalibration()
// run in standby
sam.USB_DEVICE.CTRLA |= sam.USB_DEVICE_CTRLA_RUNSTDBY
// set full speed
sam.USB_DEVICE.CTRLB |= (sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos)
// attach
sam.USB_DEVICE.CTRLB &^= sam.USB_DEVICE_CTRLB_DETACH
// enable interrupt for end of reset
sam.USB_DEVICE.INTENSET |= sam.USB_DEVICE_INTENSET_EORST
// enable interrupt for start of frame
sam.USB_DEVICE.INTENSET |= sam.USB_DEVICE_INTENSET_SOF
// enable USB
sam.USB_DEVICE.CTRLA |= sam.USB_DEVICE_CTRLA_ENABLE
// enable IRQ
arm.EnableIRQ(sam.IRQ_USB)
}
func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file.
// Modeled after defines from samd21g18a.h and nvmctrl.h:
//
// #define NVMCTRL_OTP4 0x00806020
//
// #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */
// #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos)
// #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos)))
// #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */
// #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos)
// #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos)))
// #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4)
// #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */
// #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos)
// #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos)))
//
fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4))
calibTransN := sam.RegValue16(uint16(fuse>>13) & uint16(0x1f))
calibTransP := sam.RegValue16(uint16(fuse>>18) & uint16(0x1f))
calibTrim := sam.RegValue16(uint16(fuse>>23) & uint16(0x7))
if calibTransN == 0x1f {
calibTransN = 5
}
sam.USB_DEVICE.PADCAL |= (calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos)
if calibTransP == 0x1f {
calibTransP = 29
}
sam.USB_DEVICE.PADCAL |= (calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos)
if calibTrim == 0x7 {
calibTransN = 3
}
sam.USB_DEVICE.PADCAL |= (calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
}
//go:export USB_IRQHandler
func handleUSB() {
// reset all interrupt flags
flags := sam.USB_DEVICE.INTFLAG
sam.USB_DEVICE.INTFLAG = flags
// End of reset
if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 {
// Configure control endpoint
initEndpoint(0, usb_ENDPOINT_TYPE_CONTROL)
// Enable Setup-Received interrupt
setEPINTENSET(0, sam.USB_DEVICE_EPINTENSET_RXSTP)
usbConfiguration = 0
// ack the End-Of-Reset interrupt
sam.USB_DEVICE.INTFLAG = sam.USB_DEVICE_INTFLAG_EORST
}
// Start of frame
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
// if you want to blink LED showing traffic, this would be the place...
}
// Endpoint 0 Setup interrupt
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_RXSTP > 0 {
// ack setup received
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_RXSTP)
// parse setup
setup := newUSBSetup(udd_ep_out_cache_buffer[0][:])
// Clear the Bank 0 ready flag on Control OUT
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
ok := false
if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD {
// Standard Requests
ok = handleStandardSetup(setup)
} else {
// Class Interface Requests
if setup.wIndex == usb_CDC_ACM_INTERFACE {
ok = cdcSetup(setup)
}
}
if ok {
// set Bank1 ready
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
} else {
// Stall endpoint
setEPSTATUSSET(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
}
if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_STALL1 > 0 {
// ack the stall
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_STALL1)
// clear stall request
setEPINTENCLR(0, sam.USB_DEVICE_EPINTENCLR_STALL1)
}
}
// Now the actual transfer handlers
eptInts := sam.USB_DEVICE.EPINTSMRY & 0xFE // Remove endpoint number 0 (setup)
var i uint32
for i = 1; i < uint32(len(endPoints)); i++ {
// Check if endpoint has a pending interrupt
if eptInts&(1<<i) > 0 {
// yes, so handle flags
epFlags := getEPINTFLAG(i)
setEPINTFLAG(i, epFlags)
// Endpoint Transfer Complete Interrupt
if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 {
handleEndpoint(i)
}
}
}
}
func initEndpoint(ep, config uint32) {
switch config {
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE |=
sam.RegValue(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_INTERRUPT+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
case usb_ENDPOINT_TYPE_BULK | usbEndpointOut:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE |=
sam.RegValue(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
// ack the current transfer
setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0)
// ready for next transfer
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
case usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointOut:
// TODO: not really anything, seems like...
case usb_ENDPOINT_TYPE_BULK | usbEndpointIn:
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE |=
sam.RegValue(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_BULK+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
// NAK on endpoint IN, the bank is not yet filled in.
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
case usb_ENDPOINT_TYPE_CONTROL:
// Control OUT
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE |=
sam.RegValue(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE0_Pos))
// Control IN
// set packet size
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE |=
sam.RegValue(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos)
// set data buffer address
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))
// set endpoint type
setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_CONTROL+1)<<sam.USB_DEVICE_EPCFG_EPTYPE1_Pos))
// Prepare OUT endpoint for receive
// set multi packet size for expected number of receive bytes on control OUT
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE |=
sam.RegValue(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count to zero, we have not received anything yet
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE &^=
sam.RegValue(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// NAK on endpoint OUT to show we are ready to receive control data
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK0RDY)
}
}
func handleStandardSetup(setup usbSetup) bool {
switch setup.bRequest {
case usb_GET_STATUS:
buf := []byte{0, 0}
if setup.bmRequestType != 0 { // endpoint
// TODO: actually check if the endpoint in question is currently halted
if isEndpointHalt {
buf[0] = 1
}
}
sendUSBPacket(0, buf)
return true
case usb_CLEAR_FEATURE:
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = false
} else if setup.wValueL == 0 { // ENDPOINTHALT
isEndpointHalt = false
}
sendZlp(0)
return true
case usb_SET_FEATURE:
if setup.wValueL == 1 { // DEVICEREMOTEWAKEUP
isRemoteWakeUpEnabled = true
} else if setup.wValueL == 0 { // ENDPOINTHALT
isEndpointHalt = true
}
sendZlp(0)
return true
case usb_SET_ADDRESS:
// set packet size 64 with auto Zlp after transfer
usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE =
sam.RegValue(epPacketSize(64)<<usb_DEVICE_PCKSIZE_SIZE_Pos) |
sam.RegValue(1<<31) // autozlp
// ack the transfer is complete from the request
setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
// set bank ready for data
setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
// wait for transfer to complete
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) == 0 {
}
// last, set the device address to that requested by host
sam.USB_DEVICE.DADD |= sam.RegValue8(setup.wValueL)
sam.USB_DEVICE.DADD |= sam.USB_DEVICE_DADD_ADDEN
return true
case usb_GET_DESCRIPTOR:
sendDescriptor(setup)
return true
case usb_SET_DESCRIPTOR:
return false
case usb_GET_CONFIGURATION:
buff := []byte{usbConfiguration}
sendUSBPacket(0, buff)
return true
case usb_SET_CONFIGURATION:
if setup.bmRequestType&usb_REQUEST_RECIPIENT == usb_REQUEST_DEVICE {
for i := 1; i < len(endPoints); i++ {
initEndpoint(uint32(i), endPoints[i])
}
usbConfiguration = setup.wValueL
// Enable interrupt for CDC control messages from host (OUT packet)
setEPINTENSET(usb_CDC_ENDPOINT_ACM, sam.USB_DEVICE_EPINTENSET_TRCPT1)
// Enable interrupt for CDC data messages from host
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
sendZlp(0)
return true
} else {
return false
}
case usb_GET_INTERFACE:
buff := []byte{usbSetInterface}
sendUSBPacket(0, buff)
return true
case usb_SET_INTERFACE:
usbSetInterface = setup.wValueL
sendZlp(0)
return true
default:
return true
}
}
func cdcSetup(setup usbSetup) bool {
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_GET_LINE_CODING {
buf := bytes.NewBuffer(make([]byte, 0, 7))
binary.Write(buf, binary.LittleEndian, usbLineInfo.dwDTERate)
binary.Write(buf, binary.LittleEndian, usbLineInfo.bCharFormat)
binary.Write(buf, binary.LittleEndian, usbLineInfo.bParityType)
binary.Write(buf, binary.LittleEndian, usbLineInfo.bDataBits)
sendUSBPacket(0, buf.Bytes())
return true
}
}
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_SET_LINE_CODING {
buf := bytes.NewBuffer(receiveUSBControlPacket())
binary.Read(buf, binary.LittleEndian, &(usbLineInfo.dwDTERate))
binary.Read(buf, binary.LittleEndian, &(usbLineInfo.bCharFormat))
binary.Read(buf, binary.LittleEndian, &(usbLineInfo.bParityType))
binary.Read(buf, binary.LittleEndian, &(usbLineInfo.bDataBits))
}
if setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
usbLineInfo.lineState = setup.wValueL
}
if setup.bRequest == usb_CDC_SET_LINE_CODING || setup.bRequest == usb_CDC_SET_CONTROL_LINE_STATE {
// auto-reset into the bootloader
if usbLineInfo.dwDTERate == 1200 && (usbLineInfo.lineState&0x01) == 0 {
// TODO: system reset
} else {
// TODO: cancel any reset
}
}
if setup.bRequest == usb_CDC_SEND_BREAK {
// TODO: something with this value?
// breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
// return false;
}
return true
}
return false
}
func sendUSBPacket(ep uint32, data []byte) {
copy(udd_ep_in_cache_buffer[ep][:], data)
// Set endpoint address for sending data
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))
// clear multi-packet size which is total bytes already sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE &^=
sam.RegValue(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
// set byte count, which is total number of bytes to be sent
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE |=
sam.RegValue((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func receiveUSBControlPacket() []byte {
// set ready to receive data
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
// read the data
bytesread := armRecvCtrlOUT(0)
// return the data
data := make([]byte, 0, bytesread)
copy(data, udd_ep_out_cache_buffer[0][:bytesread])
return data
}
func armRecvCtrlOUT(ep uint32) uint32 {
// Set output address to receive data
usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR =
sam.RegValue(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))
// set multi-packet size which is total expected number of bytes to receive.
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE |=
sam.RegValue(8<<usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos) |
sam.RegValue(epPacketSize(64)<<usb_DEVICE_PCKSIZE_SIZE_Pos)
// clear byte count of bytes received so far.
usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE &^=
sam.RegValue(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// clear ready state to start transfer
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
// Wait until OUT transfer is ready.
for (getEPSTATUS(ep) & sam.USB_DEVICE_EPSTATUS_BK0RDY) == 0 {
}
// Wait until OUT transfer is completed.
for (getEPINTFLAG(ep) & sam.USB_DEVICE_EPINTFLAG_TRCPT0) == 0 {
}
// return number of bytes received
return uint32((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
}
// sendDescriptor creates and sends the various USB descriptor types that
// can be requested by the host.
func sendDescriptor(setup usbSetup) {
switch setup.wValueH {
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
sendConfiguration(setup)
return
case usb_DEVICE_DESCRIPTOR_TYPE:
if setup.wLength == 8 {
// composite descriptor requested, so only send 8 bytes
dd := NewDeviceDescriptor(0xEF, 0x02, 0x01, 64, usb_VID, usb_PID, 0x100, usb_IMANUFACTURER, usb_IPRODUCT, usb_ISERIAL, 1)
sendUSBPacket(0, dd.Bytes()[:8])
} else {
// complete descriptor requested so send entire packet
dd := NewDeviceDescriptor(0x00, 0x00, 0x00, 64, usb_VID, usb_PID, 0x100, usb_IMANUFACTURER, usb_IPRODUCT, usb_ISERIAL, 1)
sendUSBPacket(0, dd.Bytes())
}
return
case usb_STRING_DESCRIPTOR_TYPE:
switch setup.wValueL {
case 0:
b := make([]byte, 4)
b[0] = byte(usb_STRING_LANGUAGE[0] >> 8)
b[1] = byte(usb_STRING_LANGUAGE[0] & 0xff)
b[2] = byte(usb_STRING_LANGUAGE[1] >> 8)
b[3] = byte(usb_STRING_LANGUAGE[1] & 0xff)
sendUSBPacket(0, b)
case usb_IPRODUCT:
prod := []byte(usb_STRING_PRODUCT)
b := make([]byte, len(prod)*2+2)
b[0] = byte(len(prod)*2 + 2)
b[1] = 0x03
for i, val := range prod {
b[i*2] = 0
b[i*2+1] = val
}
sendUSBPacket(0, b)
case usb_IMANUFACTURER:
prod := []byte(usb_STRING_MANUFACTURER)
b := make([]byte, len(prod)*2+2)
b[0] = byte(len(prod)*2 + 2)
b[1] = 0x03
for i, val := range prod {
b[i*2] = 0
b[i*2+1] = val
}
sendUSBPacket(0, b)
case usb_ISERIAL:
// TODO: allow returning a product serial number
sendZlp(0)
}
// send final zero length packet and return
sendZlp(0)
return
}
// do not know how to handle this message, so return zero
sendZlp(0)
return
}
// sendConfiguration creates and sends the configuration packet to the host.
func sendConfiguration(setup usbSetup) {
if setup.wLength == 9 {
sz := uint16(configDescriptorSize + cdcSize)
config := NewConfigDescriptor(sz, 2)
sendUSBPacket(0, config.Bytes())
} else {
iad := NewIADDescriptor(0, 2, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
cif := NewInterfaceDescriptor(usb_CDC_ACM_INTERFACE, 1, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
header := NewCDCCSInterfaceDescriptor(usb_CDC_HEADER, usb_CDC_V1_10&0xFF, (usb_CDC_V1_10>>8)&0x0FF)
controlManagement := NewACMFunctionalDescriptor(usb_CDC_ABSTRACT_CONTROL_MANAGEMENT, 6)
functionalDescriptor := NewCDCCSInterfaceDescriptor(usb_CDC_UNION, usb_CDC_ACM_INTERFACE, usb_CDC_DATA_INTERFACE)
callManagement := NewCMFunctionalDescriptor(usb_CDC_CALL_MANAGEMENT, 1, 1)
cifin := NewEndpointDescriptor((usb_CDC_ENDPOINT_ACM | usbEndpointIn), usb_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10)
dif := NewInterfaceDescriptor(usb_CDC_DATA_INTERFACE, 2, usb_CDC_DATA_INTERFACE_CLASS, 0, 0)
in := NewEndpointDescriptor((usb_CDC_ENDPOINT_OUT | usbEndpointOut), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
out := NewEndpointDescriptor((usb_CDC_ENDPOINT_IN | usbEndpointIn), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
cdc := NewCDCDescriptor(iad,
cif,
header,
controlManagement,
functionalDescriptor,
callManagement,
cifin,
dif,
in,
out)
sz := uint16(configDescriptorSize + cdcSize)
config := NewConfigDescriptor(sz, 2)
buf := make([]byte, 0, sz)
buf = append(buf, config.Bytes()...)
buf = append(buf, cdc.Bytes()...)
sendUSBPacket(0, buf)
}
}
func handleEndpoint(ep uint32) {
// get data
count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
// move to ring buffer
for i := 0; i < count; i++ {
UART0.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
}
// set ready for next data
setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
}
func sendZlp(ep uint32) {
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE &^=
sam.RegValue(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
}
func epPacketSize(size uint16) uint32 {
switch size {
case 8:
return 0
case 16:
return 1
case 32:
return 2
case 64:
return 3
case 128:
return 4
case 256:
return 5
case 512:
return 6
case 1023:
return 7
default:
return 0
}
}
func getEPCFG(ep uint32) sam.RegValue8 {
switch ep {
case 0:
return sam.USB_DEVICE.EPCFG0
case 1:
return sam.USB_DEVICE.EPCFG1
case 2:
return sam.USB_DEVICE.EPCFG2
case 3:
return sam.USB_DEVICE.EPCFG3
case 4:
return sam.USB_DEVICE.EPCFG4
case 5:
return sam.USB_DEVICE.EPCFG5
case 6:
return sam.USB_DEVICE.EPCFG6
case 7:
return sam.USB_DEVICE.EPCFG7
default:
return 0
}
}
func setEPCFG(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPCFG0 = val
case 1:
sam.USB_DEVICE.EPCFG1 = val
case 2:
sam.USB_DEVICE.EPCFG2 = val
case 3:
sam.USB_DEVICE.EPCFG3 = val
case 4:
sam.USB_DEVICE.EPCFG4 = val
case 5:
sam.USB_DEVICE.EPCFG5 = val
case 6:
sam.USB_DEVICE.EPCFG6 = val
case 7:
sam.USB_DEVICE.EPCFG7 = val
default:
return
}
}
func setEPSTATUSCLR(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPSTATUSCLR0 = val
case 1:
sam.USB_DEVICE.EPSTATUSCLR1 = val
case 2:
sam.USB_DEVICE.EPSTATUSCLR2 = val
case 3:
sam.USB_DEVICE.EPSTATUSCLR3 = val
case 4:
sam.USB_DEVICE.EPSTATUSCLR4 = val
case 5:
sam.USB_DEVICE.EPSTATUSCLR5 = val
case 6:
sam.USB_DEVICE.EPSTATUSCLR6 = val
case 7:
sam.USB_DEVICE.EPSTATUSCLR7 = val
default:
return
}
}
func setEPSTATUSSET(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPSTATUSSET0 = val
case 1:
sam.USB_DEVICE.EPSTATUSSET1 = val
case 2:
sam.USB_DEVICE.EPSTATUSSET2 = val
case 3:
sam.USB_DEVICE.EPSTATUSSET3 = val
case 4:
sam.USB_DEVICE.EPSTATUSSET4 = val
case 5:
sam.USB_DEVICE.EPSTATUSSET5 = val
case 6:
sam.USB_DEVICE.EPSTATUSSET6 = val
case 7:
sam.USB_DEVICE.EPSTATUSSET7 = val
default:
return
}
}
func getEPSTATUS(ep uint32) sam.RegValue8 {
switch ep {
case 0:
return sam.USB_DEVICE.EPSTATUS0
case 1:
return sam.USB_DEVICE.EPSTATUS1
case 2:
return sam.USB_DEVICE.EPSTATUS2
case 3:
return sam.USB_DEVICE.EPSTATUS3
case 4:
return sam.USB_DEVICE.EPSTATUS4
case 5:
return sam.USB_DEVICE.EPSTATUS5
case 6:
return sam.USB_DEVICE.EPSTATUS6
case 7:
return sam.USB_DEVICE.EPSTATUS7
default:
return 0
}
}
func getEPINTFLAG(ep uint32) sam.RegValue8 {
switch ep {
case 0:
return sam.USB_DEVICE.EPINTFLAG0
case 1:
return sam.USB_DEVICE.EPINTFLAG1
case 2:
return sam.USB_DEVICE.EPINTFLAG2
case 3:
return sam.USB_DEVICE.EPINTFLAG3
case 4:
return sam.USB_DEVICE.EPINTFLAG4
case 5:
return sam.USB_DEVICE.EPINTFLAG5
case 6:
return sam.USB_DEVICE.EPINTFLAG6
case 7:
return sam.USB_DEVICE.EPINTFLAG7
default:
return 0
}
}
func setEPINTFLAG(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPINTFLAG0 = val
case 1:
sam.USB_DEVICE.EPINTFLAG1 = val
case 2:
sam.USB_DEVICE.EPINTFLAG2 = val
case 3:
sam.USB_DEVICE.EPINTFLAG3 = val
case 4:
sam.USB_DEVICE.EPINTFLAG4 = val
case 5:
sam.USB_DEVICE.EPINTFLAG5 = val
case 6:
sam.USB_DEVICE.EPINTFLAG6 = val
case 7:
sam.USB_DEVICE.EPINTFLAG7 = val
default:
return
}
}
func setEPINTENCLR(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPINTENCLR0 = val
case 1:
sam.USB_DEVICE.EPINTENCLR1 = val
case 2:
sam.USB_DEVICE.EPINTENCLR2 = val
case 3:
sam.USB_DEVICE.EPINTENCLR3 = val
case 4:
sam.USB_DEVICE.EPINTENCLR4 = val
case 5:
sam.USB_DEVICE.EPINTENCLR5 = val
case 6:
sam.USB_DEVICE.EPINTENCLR6 = val
case 7:
sam.USB_DEVICE.EPINTENCLR7 = val
default:
return
}
}
func setEPINTENSET(ep uint32, val sam.RegValue8) {
switch ep {
case 0:
sam.USB_DEVICE.EPINTENSET0 = val
case 1:
sam.USB_DEVICE.EPINTENSET1 = val
case 2:
sam.USB_DEVICE.EPINTENSET2 = val
case 3:
sam.USB_DEVICE.EPINTENSET3 = val
case 4:
sam.USB_DEVICE.EPINTENSET4 = val
case 5:
sam.USB_DEVICE.EPINTENSET5 = val
case 6:
sam.USB_DEVICE.EPINTENSET6 = val
case 7:
sam.USB_DEVICE.EPINTENSET7 = val
default:
return
}
}

599
src/machine/usb.go Обычный файл
Просмотреть файл

@ -0,0 +1,599 @@
// +build sam
package machine
import (
"bytes"
"device/sam"
"encoding/binary"
"errors"
)
const deviceDescriptorSize = 18
// DeviceDescriptor implements the USB standard device descriptor.
//
// Table 9-8. Standard Device Descriptor
// bLength, bDescriptorType, bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0,
// idVendor, idProduct, bcdDevice, iManufacturer, iProduct, iSerialNumber, bNumConfigurations */
//
type DeviceDescriptor struct {
bLength uint8 // 18
bDescriptorType uint8 // 1 USB_DEVICE_DESCRIPTOR_TYPE
bcdUSB uint16 // 0x200
bDeviceClass uint8
bDeviceSubClass uint8
bDeviceProtocol uint8
bMaxPacketSize0 uint8 // Packet 0
idVendor uint16
idProduct uint16
bcdDevice uint16 // 0x100
iManufacturer uint8
iProduct uint8
iSerialNumber uint8
bNumConfigurations uint8
}
// NewDeviceDescriptor returns a USB DeviceDescriptor.
func NewDeviceDescriptor(class, subClass, proto, packetSize0 uint8, vid, pid, version uint16, im, ip, is, configs uint8) DeviceDescriptor {
return DeviceDescriptor{deviceDescriptorSize, 1, 0x200, class, subClass, proto, packetSize0, vid, pid, version, im, ip, is, configs}
}
// Bytes returns DeviceDescriptor data
func (d DeviceDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, deviceDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.bcdUSB)
binary.Write(buf, binary.LittleEndian, d.bDeviceClass)
binary.Write(buf, binary.LittleEndian, d.bDeviceSubClass)
binary.Write(buf, binary.LittleEndian, d.bDeviceProtocol)
binary.Write(buf, binary.LittleEndian, d.bMaxPacketSize0)
binary.Write(buf, binary.LittleEndian, d.idVendor)
binary.Write(buf, binary.LittleEndian, d.idProduct)
binary.Write(buf, binary.LittleEndian, d.bcdDevice)
binary.Write(buf, binary.LittleEndian, d.iManufacturer)
binary.Write(buf, binary.LittleEndian, d.iProduct)
binary.Write(buf, binary.LittleEndian, d.iSerialNumber)
binary.Write(buf, binary.LittleEndian, d.bNumConfigurations)
return buf.Bytes()
}
const configDescriptorSize = 9
// ConfigDescriptor implements the standard USB configuration descriptor.
//
// Table 9-10. Standard Configuration Descriptor
// bLength, bDescriptorType, wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration
// bmAttributes, bMaxPower
//
type ConfigDescriptor struct {
bLength uint8 // 9
bDescriptorType uint8 // 2
wTotalLength uint16 // total length
bNumInterfaces uint8
bConfigurationValue uint8
iConfiguration uint8
bmAttributes uint8
bMaxPower uint8
}
// NewConfigDescriptor returns a new USB ConfigDescriptor.
func NewConfigDescriptor(totalLength uint16, interfaces uint8) ConfigDescriptor {
return ConfigDescriptor{configDescriptorSize, 2, totalLength, interfaces, 1, 0, usb_CONFIG_BUS_POWERED | usb_CONFIG_REMOTE_WAKEUP, 50}
}
// Bytes returns ConfigDescriptor data.
func (d ConfigDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, configDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.wTotalLength)
binary.Write(buf, binary.LittleEndian, d.bNumInterfaces)
binary.Write(buf, binary.LittleEndian, d.bConfigurationValue)
binary.Write(buf, binary.LittleEndian, d.iConfiguration)
binary.Write(buf, binary.LittleEndian, d.bmAttributes)
binary.Write(buf, binary.LittleEndian, d.bMaxPower)
return buf.Bytes()
}
const interfaceDescriptorSize = 9
// InterfaceDescriptor implements the standard USB interface descriptor.
//
// Table 9-12. Standard Interface Descriptor
// bLength, bDescriptorType, bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass,
// bInterfaceSubClass, bInterfaceProtocol, iInterface
//
type InterfaceDescriptor struct {
bLength uint8 // 9
bDescriptorType uint8 // 4
bInterfaceNumber uint8
bAlternateSetting uint8
bNumEndpoints uint8
bInterfaceClass uint8
bInterfaceSubClass uint8
bInterfaceProtocol uint8
iInterface uint8
}
// NewInterfaceDescriptor returns a new USB InterfaceDescriptor.
func NewInterfaceDescriptor(n, numEndpoints, class, subClass, protocol uint8) InterfaceDescriptor {
return InterfaceDescriptor{interfaceDescriptorSize, 4, n, 0, numEndpoints, class, subClass, protocol, 0}
}
// Bytes returns InterfaceDescriptor data.
func (d InterfaceDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, interfaceDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.bInterfaceNumber)
binary.Write(buf, binary.LittleEndian, d.bAlternateSetting)
binary.Write(buf, binary.LittleEndian, d.bNumEndpoints)
binary.Write(buf, binary.LittleEndian, d.bInterfaceClass)
binary.Write(buf, binary.LittleEndian, d.bInterfaceSubClass)
binary.Write(buf, binary.LittleEndian, d.bInterfaceProtocol)
binary.Write(buf, binary.LittleEndian, d.iInterface)
return buf.Bytes()
}
const endpointDescriptorSize = 7
// EndpointDescriptor implements the standard USB endpoint descriptor.
//
// Table 9-13. Standard Endpoint Descriptor
// bLength, bDescriptorType, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval
//
type EndpointDescriptor struct {
bLength uint8 // 7
bDescriptorType uint8 // 5
bEndpointAddress uint8
bmAttributes uint8
wMaxPacketSize uint16
bInterval uint8
}
// NewEndpointDescriptor returns a new USB EndpointDescriptor.
func NewEndpointDescriptor(addr, attr uint8, packetSize uint16, interval uint8) EndpointDescriptor {
return EndpointDescriptor{endpointDescriptorSize, 5, addr, attr, packetSize, interval}
}
// Bytes returns EndpointDescriptor data.
func (d EndpointDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, endpointDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.bEndpointAddress)
binary.Write(buf, binary.LittleEndian, d.bmAttributes)
binary.Write(buf, binary.LittleEndian, d.wMaxPacketSize)
binary.Write(buf, binary.LittleEndian, d.bInterval)
return buf.Bytes()
}
const iadDescriptorSize = 8
// IADDescriptor is an Interface Association Descriptor, which is used
// to bind 2 interfaces together in CDC composite device.
//
// Standard Interface Association Descriptor:
// bLength, bDescriptorType, bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass,
// bFunctionProtocol, iFunction
//
type IADDescriptor struct {
bLength uint8 // 8
bDescriptorType uint8 // 11
bFirstInterface uint8
bInterfaceCount uint8
bFunctionClass uint8
bFunctionSubClass uint8
bFunctionProtocol uint8
iFunction uint8
}
// NewIADDescriptor returns a new USB IADDescriptor.
func NewIADDescriptor(firstInterface, count, class, subClass, protocol uint8) IADDescriptor {
return IADDescriptor{iadDescriptorSize, 11, firstInterface, count, class, subClass, protocol, 0}
}
// Bytes returns IADDescriptor data.
func (d IADDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, iadDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.bFirstInterface)
binary.Write(buf, binary.LittleEndian, d.bInterfaceCount)
binary.Write(buf, binary.LittleEndian, d.bFunctionClass)
binary.Write(buf, binary.LittleEndian, d.bFunctionSubClass)
binary.Write(buf, binary.LittleEndian, d.bFunctionProtocol)
binary.Write(buf, binary.LittleEndian, d.iFunction)
return buf.Bytes()
}
const cdcCSInterfaceDescriptorSize = 5
// CDCCSInterfaceDescriptor is a CDC CS interface descriptor.
type CDCCSInterfaceDescriptor struct {
len uint8 // 5
dtype uint8 // 0x24
subtype uint8
d0 uint8
d1 uint8
}
// NewCDCCSInterfaceDescriptor returns a new USB CDCCSInterfaceDescriptor.
func NewCDCCSInterfaceDescriptor(subtype, d0, d1 uint8) CDCCSInterfaceDescriptor {
return CDCCSInterfaceDescriptor{cdcCSInterfaceDescriptorSize, 0x24, subtype, d0, d1}
}
// Bytes returns CDCCSInterfaceDescriptor data.
func (d CDCCSInterfaceDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, cdcCSInterfaceDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.len)
binary.Write(buf, binary.LittleEndian, d.dtype)
binary.Write(buf, binary.LittleEndian, d.subtype)
binary.Write(buf, binary.LittleEndian, d.d0)
binary.Write(buf, binary.LittleEndian, d.d1)
return buf.Bytes()
}
const cmFunctionalDescriptorSize = 5
// CMFunctionalDescriptor is the functional descriptor general format.
type CMFunctionalDescriptor struct {
bFunctionLength uint8
bDescriptorType uint8 // 0x24
bDescriptorSubtype uint8 // 1
bmCapabilities uint8
bDataInterface uint8
}
// NewCMFunctionalDescriptor returns a new USB CMFunctionalDescriptor.
func NewCMFunctionalDescriptor(subtype, d0, d1 uint8) CMFunctionalDescriptor {
return CMFunctionalDescriptor{5, 0x24, subtype, d0, d1}
}
// Bytes returns the CMFunctionalDescriptor data.
func (d CMFunctionalDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, cmFunctionalDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.bFunctionLength)
binary.Write(buf, binary.LittleEndian, d.bDescriptorType)
binary.Write(buf, binary.LittleEndian, d.bDescriptorSubtype)
binary.Write(buf, binary.LittleEndian, d.bmCapabilities)
binary.Write(buf, binary.LittleEndian, d.bDataInterface)
return buf.Bytes()
}
const acmFunctionalDescriptorSize = 4
// ACMFunctionalDescriptor is a Abstract Control Model (ACM) USB descriptor.
type ACMFunctionalDescriptor struct {
len uint8
dtype uint8 // 0x24
subtype uint8 // 1
bmCapabilities uint8
}
// NewACMFunctionalDescriptor returns a new USB ACMFunctionalDescriptor.
func NewACMFunctionalDescriptor(subtype, d0 uint8) ACMFunctionalDescriptor {
return ACMFunctionalDescriptor{4, 0x24, subtype, d0}
}
// Bytes returns the ACMFunctionalDescriptor data.
func (d ACMFunctionalDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, acmFunctionalDescriptorSize))
binary.Write(buf, binary.LittleEndian, d.len)
binary.Write(buf, binary.LittleEndian, d.dtype)
binary.Write(buf, binary.LittleEndian, d.subtype)
binary.Write(buf, binary.LittleEndian, d.bmCapabilities)
return buf.Bytes()
}
// CDCDescriptor is the Communication Device Class (CDC) descriptor.
type CDCDescriptor struct {
// IAD
iad IADDescriptor // Only needed on compound device
// Control
cif InterfaceDescriptor
header CDCCSInterfaceDescriptor
// CDC control
controlManagement ACMFunctionalDescriptor // ACM
functionalDescriptor CDCCSInterfaceDescriptor // CDC_UNION
callManagement CMFunctionalDescriptor // Call Management
cifin EndpointDescriptor
// CDC Data
dif InterfaceDescriptor
in EndpointDescriptor
out EndpointDescriptor
}
func NewCDCDescriptor(i IADDescriptor, c InterfaceDescriptor,
h CDCCSInterfaceDescriptor,
cm ACMFunctionalDescriptor,
fd CDCCSInterfaceDescriptor,
callm CMFunctionalDescriptor,
ci EndpointDescriptor,
di InterfaceDescriptor,
inp EndpointDescriptor,
outp EndpointDescriptor) CDCDescriptor {
return CDCDescriptor{iad: i,
cif: c,
header: h,
controlManagement: cm,
functionalDescriptor: fd,
callManagement: callm,
cifin: ci,
dif: di,
in: inp,
out: outp}
}
const cdcSize = iadDescriptorSize +
interfaceDescriptorSize +
cdcCSInterfaceDescriptorSize +
acmFunctionalDescriptorSize +
cdcCSInterfaceDescriptorSize +
cmFunctionalDescriptorSize +
endpointDescriptorSize +
interfaceDescriptorSize +
endpointDescriptorSize +
endpointDescriptorSize
// Bytes returns CDCDescriptor data.
func (d CDCDescriptor) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, cdcSize))
buf.Write(d.iad.Bytes())
buf.Write(d.cif.Bytes())
buf.Write(d.header.Bytes())
buf.Write(d.controlManagement.Bytes())
buf.Write(d.functionalDescriptor.Bytes())
buf.Write(d.callManagement.Bytes())
buf.Write(d.cifin.Bytes())
buf.Write(d.dif.Bytes())
buf.Write(d.in.Bytes())
buf.Write(d.out.Bytes())
return buf.Bytes()
}
// MSCDescriptor is not used yet.
type MSCDescriptor struct {
msc InterfaceDescriptor
in EndpointDescriptor
out EndpointDescriptor
}
type cdcLineInfo struct {
dwDTERate uint32
bCharFormat uint8
bParityType uint8
bDataBits uint8
lineState uint8
}
var (
// TODO: allow setting these
usb_STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English
usb_STRING_PRODUCT = "Arduino Zero"
usb_STRING_MANUFACTURER = "Arduino"
usb_VID uint16 = 0x2341
usb_PID uint16 = 0x004d
)
const (
usb_IMANUFACTURER = 1
usb_IPRODUCT = 2
usb_ISERIAL = 3
usb_ENDPOINT_TYPE_CONTROL = 0x00
usb_ENDPOINT_TYPE_ISOCHRONOUS = 0x01
usb_ENDPOINT_TYPE_BULK = 0x02
usb_ENDPOINT_TYPE_INTERRUPT = 0x03
usb_DEVICE_DESCRIPTOR_TYPE = 1
usb_CONFIGURATION_DESCRIPTOR_TYPE = 2
usb_STRING_DESCRIPTOR_TYPE = 3
usb_INTERFACE_DESCRIPTOR_TYPE = 4
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
usb_DEVICE_QUALIFIER = 6
usb_OTHER_SPEED_CONFIGURATION = 7
usbEndpointOut = 0x00
usbEndpointIn = 0x80
usbEndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024
usb_EPT_NUM = 7
// standard requests
usb_GET_STATUS = 0
usb_CLEAR_FEATURE = 1
usb_SET_FEATURE = 3
usb_SET_ADDRESS = 5
usb_GET_DESCRIPTOR = 6
usb_SET_DESCRIPTOR = 7
usb_GET_CONFIGURATION = 8
usb_SET_CONFIGURATION = 9
usb_GET_INTERFACE = 10
usb_SET_INTERFACE = 11
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
usb_DEVICE_CLASS_STORAGE = 0x08
usb_DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF
usb_CONFIG_POWERED_MASK = 0x40
usb_CONFIG_BUS_POWERED = 0x80
usb_CONFIG_SELF_POWERED = 0xC0
usb_CONFIG_REMOTE_WAKEUP = 0x20
// CDC
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
usb_CDC_DATA_INTERFACE = 1 // CDC Data
usb_CDC_FIRST_ENDPOINT = 1
usb_CDC_ENDPOINT_ACM = 1
usb_CDC_ENDPOINT_OUT = 2
usb_CDC_ENDPOINT_IN = 3
// bmRequestType
usb_REQUEST_HOSTTODEVICE = 0x00
usb_REQUEST_DEVICETOHOST = 0x80
usb_REQUEST_DIRECTION = 0x80
usb_REQUEST_STANDARD = 0x00
usb_REQUEST_CLASS = 0x20
usb_REQUEST_VENDOR = 0x40
usb_REQUEST_TYPE = 0x60
usb_REQUEST_DEVICE = 0x00
usb_REQUEST_INTERFACE = 0x01
usb_REQUEST_ENDPOINT = 0x02
usb_REQUEST_OTHER = 0x03
usb_REQUEST_RECIPIENT = 0x1F
usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE)
// 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
)
// usbDeviceDescBank is the USB device endpoint descriptor.
// typedef struct {
// __IO USB_DEVICE_ADDR_Type ADDR; /**< \brief Offset: 0x000 (R/W 32) DEVICE_DESC_BANK Endpoint Bank, Adress of Data Buffer */
// __IO USB_DEVICE_PCKSIZE_Type PCKSIZE; /**< \brief Offset: 0x004 (R/W 32) DEVICE_DESC_BANK Endpoint Bank, Packet Size */
// __IO USB_DEVICE_EXTREG_Type EXTREG; /**< \brief Offset: 0x008 (R/W 16) DEVICE_DESC_BANK Endpoint Bank, Extended */
// __IO USB_DEVICE_STATUS_BK_Type STATUS_BK; /**< \brief Offset: 0x00A (R/W 8) DEVICE_DESC_BANK Enpoint Bank, Status of Bank */
// RoReg8 Reserved1[0x5];
// } UsbDeviceDescBank;
type usbDeviceDescBank struct {
ADDR sam.RegValue
PCKSIZE sam.RegValue
EXTREG sam.RegValue16
STATUS_BK sam.RegValue8
_reserved [5]sam.RegValue8
}
type usbDeviceDescriptor struct {
DeviceDescBank [2]usbDeviceDescBank
}
// typedef struct {
// union {
// uint8_t bmRequestType;
// struct {
// uint8_t direction : 5;
// uint8_t type : 2;
// uint8_t transferDirection : 1;
// };
// };
// uint8_t bRequest;
// uint8_t wValueL;
// uint8_t wValueH;
// uint16_t wIndex;
// uint16_t wLength;
// } USBSetup;
type usbSetup struct {
bmRequestType uint8
bRequest uint8
wValueL uint8
wValueH uint8
wIndex uint16
wLength uint16
}
func newUSBSetup(data []byte) usbSetup {
buf := bytes.NewBuffer(data)
u := usbSetup{}
binary.Read(buf, binary.LittleEndian, &(u.bmRequestType))
binary.Read(buf, binary.LittleEndian, &(u.bRequest))
binary.Read(buf, binary.LittleEndian, &(u.wValueL))
binary.Read(buf, binary.LittleEndian, &(u.wValueH))
binary.Read(buf, binary.LittleEndian, &(u.wIndex))
binary.Read(buf, binary.LittleEndian, &(u.wLength))
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, errors.New("Buffer empty")
}
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)
}

Просмотреть файл

@ -24,8 +24,9 @@ func init() {
initRTC()
initUARTClock()
initI2CClock()
initUSBClock()
// connect to UART
// connect to USB CDC interface
machine.UART0.Configure(machine.UARTConfig{})
}
@ -331,3 +332,14 @@ func initI2CClock() {
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
}
func initUSBClock() {
// Turn on clock for USB
sam.PM.APBBMASK |= sam.PM_APBBMASK_USB_
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_USB << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
}