diff --git a/builder/sizes_test.go b/builder/sizes_test.go index a51a371d81..f7ee7e1b27 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -44,7 +44,7 @@ func TestBinarySize(t *testing.T) { // microcontrollers {"hifive1b", "examples/echo", 3817, 299, 0, 2252}, {"microbit", "examples/serial", 2820, 356, 8, 2248}, - {"wioterminal", "examples/pininterrupt", 8036, 1652, 132, 7480}, + {"wioterminal", "examples/pininterrupt", 8020, 1652, 132, 7480}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/machine/machine_atsamd21_usb.go b/src/machine/machine_atsamd21_usb.go index 28e8c6d223..45ba18d454 100644 --- a/src/machine/machine_atsamd21_usb.go +++ b/src/machine/machine_atsamd21_usb.go @@ -175,7 +175,7 @@ func handleUSBIRQ(intr interrupt.Interrupt) { // Now the actual transfer handlers, ignore endpoint number 0 (setup) var i uint32 - for i = 1; i < uint32(len(endPoints)); i++ { + for i = 1; i < NumberOfUSBEndpoints; i++ { // Check if endpoint has a pending interrupt epFlags := getEPINTFLAG(i) setEPINTFLAG(i, epFlags) @@ -193,6 +193,8 @@ func handleUSBIRQ(intr interrupt.Interrupt) { } func initEndpoint(ep, config uint32) { + // Note: Both IN (Bank 1) and OUT (Bank 0) configurations share the same EPCFG register. + // We must use getEPCFG(ep) | ... to avoid clearing/disabling the opposite direction. switch config { case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: // set packet size @@ -202,7 +204,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos)) + setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_INTERRUPT+1)< 0 outDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPOUT1<<(i-1)) > 0 @@ -191,7 +191,7 @@ func handleUSBIRQ(interrupt.Interrupt) { } // ENDEPOUT[n] events - for i := 0; i < len(endPoints); i++ { + for i := 0; i < NumberOfUSBEndpoints; i++ { if nrf.USBD.EVENTS_ENDEPOUT[i].Get() > 0 { nrf.USBD.EVENTS_ENDEPOUT[i].Set(0) buf := handleEndpointRx(uint32(i)) @@ -367,3 +367,19 @@ func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { return b, nil } + +func (dev *USBDevice) SetStallEPIn(ep uint32) { + nrf.USBD.EPSTALL.Set(ep | nrf.USBD_EPSTALL_IO | nrf.USBD_EPSTALL_STALL) +} + +func (dev *USBDevice) SetStallEPOut(ep uint32) { + nrf.USBD.EPSTALL.Set(ep | nrf.USBD_EPSTALL_STALL) +} + +func (dev *USBDevice) ClearStallEPIn(ep uint32) { + nrf.USBD.EPSTALL.Set(ep | nrf.USBD_EPSTALL_IO) +} + +func (dev *USBDevice) ClearStallEPOut(ep uint32) { + nrf.USBD.EPSTALL.Set(ep) +} diff --git a/src/machine/machine_rp2_usb.go b/src/machine/machine_rp2_usb.go index bf0e20b41c..8a90aacea7 100644 --- a/src/machine/machine_rp2_usb.go +++ b/src/machine/machine_rp2_usb.go @@ -20,38 +20,56 @@ var ( func initEndpoint(ep, config uint32) { val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff) + + // Each endpoint has 128 bytes of DPRAM buffer space allocated (2 * usbBufferLen). + // To support bidirectional configurations using the same endpoint number, + // we allocate the first 64 bytes (Buffer0) to OUT transfers, and the remaining + // 64 bytes (Buffer1) to IN transfers by shifting the IN offset by usbBufferLen. offset := ep*2*usbBufferLen + 0x100 - val |= offset // Bulk and interrupt endpoints must have their Packet ID reset to DATA0 when un-stalled. - epXPIDReset[ep] = false // Default to false in case an endpoint is re-initialized. + // Since both directions share the same ep, we reset their PID flags independently. + if (config & usb.EndpointIn) != 0 { + epXPIDResetIn[ep] = false + } else { + epXPIDResetOut[ep] = false + } switch config { case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: + epXPIDResetIn[ep] = true + epXdata0In[ep] = false + val |= offset + usbBufferLen val |= usbEpControlEndpointTypeInterrupt _usbDPSRAM.EPxControl[ep].In.Set(val) - epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: + epXPIDResetOut[ep] = true + epXdata0Out[ep] = false + val |= offset val |= usbEpControlEndpointTypeBulk _usbDPSRAM.EPxControl[ep].Out.Set(val) _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut: + epXPIDResetOut[ep] = true + epXdata0Out[ep] = false + val |= offset val |= usbEpControlEndpointTypeInterrupt _usbDPSRAM.EPxControl[ep].Out.Set(val) _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: + epXPIDResetIn[ep] = true + epXdata0In[ep] = false + val |= offset + usbBufferLen val |= usbEpControlEndpointTypeBulk _usbDPSRAM.EPxControl[ep].In.Set(val) - epXPIDReset[ep] = true case usb.ENDPOINT_TYPE_CONTROL: + val |= offset val |= usbEpControlEndpointTypeControl _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid) _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) @@ -79,7 +97,7 @@ func sendUSBPacket(ep uint32, data []byte) { } else { sendOnEP0DATADONE.offset = 0 } - epXdata0[ep] = true + epXdata0In[ep] = true } sendViaEPIn(ep, data, count) @@ -116,19 +134,29 @@ func handleEndpointRx(ep uint32) []byte { // AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. func AckUsbOutTransfer(ep uint32) { ep = ep & 0x7F - setEPDataPID(ep, !epXdata0[ep]) + setEPDataPIDOut(ep, !epXdata0Out[ep]) } -// Set the USB endpoint Packet ID to DATA0 or DATA1. -func setEPDataPID(ep uint32, dataOne bool) { - epXdata0[ep] = dataOne - if epXdata0[ep] || ep == 0 { +// Set the USB endpoint Packet ID to DATA0 or DATA1 for OUT direction. +func setEPDataPIDOut(ep uint32, dataOne bool) { + epXdata0Out[ep] = dataOne + if epXdata0Out[ep] || ep == 0 { _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) } _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) } +// Set the USB endpoint Packet ID to DATA0 or DATA1 for IN direction. +func setEPDataPIDIn(ep uint32, dataOne bool) { + epXdata0In[ep] = dataOne + if epXdata0In[ep] || ep == 0 { + _usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlData1Pid) + } + + _usbDPSRAM.EPxBufferControl[ep].In.SetBits(usbBuf0CtrlAvail) +} + func SendZlp() { sendUSBPacket(0, nil) } @@ -138,15 +166,19 @@ func sendViaEPIn(ep uint32, data []byte, count int) { val := uint32(count) | usbBuf0CtrlAvail // DATA0 or DATA1 - epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] - if !epXdata0[ep&0x7F] { + epXdata0In[ep&0x7F] = !epXdata0In[ep&0x7F] + if !epXdata0In[ep&0x7F] { val |= usbBuf0CtrlData1Pid } // Mark as full val |= usbBuf0CtrlFull - copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) + if (ep & 0x7F) == 0 { + copy(_usbDPSRAM.EPxBuffer[0].Buffer0[:], data[:count]) + } else { + copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer1[:], data[:count]) + } _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) } @@ -178,9 +210,9 @@ func (dev *USBDevice) ClearStallEPIn(ep uint32) { ep = ep & 0x7F val := uint32(usbBuf0CtrlStall) _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) - if epXPIDReset[ep] { + if epXPIDResetIn[ep] { // Reset the PID to DATA0 - setEPDataPID(ep, false) + setEPDataPIDIn(ep, false) } } @@ -189,9 +221,9 @@ func (dev *USBDevice) ClearStallEPOut(ep uint32) { ep = ep & 0x7F val := uint32(usbBuf0CtrlStall) _usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val) - if epXPIDReset[ep] { + if epXPIDResetOut[ep] { // Reset the PID to DATA0 - setEPDataPID(ep, false) + setEPDataPIDOut(ep, false) } } @@ -219,10 +251,12 @@ type usbBuffer struct { } var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - epXPIDReset [16]bool - setupBytes [8]byte + _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) + epXdata0In [16]bool + epXdata0Out [16]bool + epXPIDResetIn [16]bool + epXPIDResetOut [16]bool + setupBytes [8]byte ) func (d *usbDPSRAM) setupBytes() []byte { diff --git a/src/machine/usb/cdc/cdc.go b/src/machine/usb/cdc/cdc.go index 44bd7f7e0e..78b9c74e99 100644 --- a/src/machine/usb/cdc/cdc.go +++ b/src/machine/usb/cdc/cdc.go @@ -2,10 +2,14 @@ package cdc +import ( + "machine/usb" +) + const ( - cdcEndpointACM = 1 - cdcEndpointOut = 2 - cdcEndpointIn = 3 + cdcEndpointACM = usb.CDC_ENDPOINT_ACM + cdcEndpointOut = usb.CDC_ENDPOINT_OUT + cdcEndpointIn = usb.CDC_ENDPOINT_IN ) // New returns USBCDC struct. diff --git a/src/machine/usb/descriptor/cdc.go b/src/machine/usb/descriptor/cdc.go index ec72186e3a..d32611ca7b 100644 --- a/src/machine/usb/descriptor/cdc.go +++ b/src/machine/usb/descriptor/cdc.go @@ -150,6 +150,9 @@ var InterfaceCDCData = InterfaceType{ data: interfaceCDCData[:], } +// EP1 IN : CDC Call Management +// EP2 OUT: CDC OUT +// EP2 IN : CDC IN var CDC = Descriptor{ Device: DeviceCDC.Bytes(), Configuration: Append([][]byte{ @@ -160,9 +163,9 @@ var CDC = Descriptor{ ClassSpecificCDCCallManagement.Bytes(), ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), - EndpointEP1IN.Bytes(), + EndpointIN(EndpointEP1, TransferTypeInterrupt, 0x10, 0x10).Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointOUT(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), + EndpointIN(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), }), } diff --git a/src/machine/usb/descriptor/endpoint.go b/src/machine/usb/descriptor/endpoint.go index 57a17060c4..c918caed1e 100644 --- a/src/machine/usb/descriptor/endpoint.go +++ b/src/machine/usb/descriptor/endpoint.go @@ -15,104 +15,44 @@ const ( TransferTypeInterrupt ) -var endpointEP1IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x81, // EndpointAddress - 0x03, // Attributes - 0x10, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x10, // Interval -} - -var EndpointEP1IN = EndpointType{ - data: endpointEP1IN[:], -} - -var endpointEP2OUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x02, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointEP2OUT = EndpointType{ - data: endpointEP2OUT[:], -} +type EndpointNumber uint8 -var endpointEP3IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x83, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointEP3IN = EndpointType{ - data: endpointEP3IN[:], -} - -var endpointEP4IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x84, // EndpointAddress - 0x03, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x01, // Interval -} - -var EndpointEP4IN = EndpointType{ - data: endpointEP4IN[:], -} - -var endpointEP5OUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x05, // EndpointAddress - 0x03, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x01, // Interval -} - -var EndpointEP5OUT = EndpointType{ - data: endpointEP5OUT[:], -} - -// Mass Storage Class bulk in endpoint -var endpointMSCIN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x86, // EndpointAddress - TransferTypeBulk, // Attributes - 0x40, // MaxPacketSizeL (64 bytes) - 0x00, // MaxPacketSizeH - 0x00, // Interval -} +const ( + EndpointEP1 EndpointNumber = iota + EndpointEP2 + EndpointEP3 + EndpointEP4 +) -var EndpointMSCIN = EndpointType{ - data: endpointMSCIN[:], -} +const ( + maxEndpoints = 4 +) -// Mass Storage Class bulk out endpoint -var endpointMSCOUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x07, // EndpointAddress - TransferTypeBulk, // Attributes - 0x40, // MaxPacketSizeL (64 bytes) - 0x00, // MaxPacketSizeH - 0x00, // Interval -} +var ( + endpointEPIn = [maxEndpoints][endpointTypeLen]byte{} + endpointEPOut = [maxEndpoints][endpointTypeLen]byte{} +) -var EndpointMSCOUT = EndpointType{ - data: endpointMSCOUT[:], +func EndpointIN(ep EndpointNumber, transferType uint8, maxPacketSize uint16, interval uint8) EndpointType { + e := EndpointType{data: endpointEPIn[ep][:]} + e.Length(endpointTypeLen) + e.Type(TypeEndpoint) + e.EndpointAddress(uint8(ep+1) | 0x80) // EndpointNumber is 0-based, addresses are 1-based + e.Attributes(transferType) + e.MaxPacketSize(maxPacketSize) + e.Interval(interval) + return e +} + +func EndpointOUT(ep EndpointNumber, transferType uint8, maxPacketSize uint16, interval uint8) EndpointType { + e := EndpointType{data: endpointEPOut[ep][:]} + e.Length(endpointTypeLen) + e.Type(TypeEndpoint) + e.EndpointAddress(uint8(ep + 1)) // EndpointNumber is 0-based, addresses are 1-based + e.Attributes(transferType) + e.MaxPacketSize(maxPacketSize) + e.Interval(interval) + return e } const ( diff --git a/src/machine/usb/descriptor/hid.go b/src/machine/usb/descriptor/hid.go index 06b9801530..6ee9683c0c 100644 --- a/src/machine/usb/descriptor/hid.go +++ b/src/machine/usb/descriptor/hid.go @@ -111,6 +111,11 @@ var ClassHID = ClassHIDType{ data: classHID[:], } +// EP1 IN : CDC Call Management +// EP2 OUT: CDC OUT +// EP2 IN : CDC IN +// EP3 OUT: HID OUT +// EP3 IN : HID IN var CDCHID = Descriptor{ Device: DeviceCDC.Bytes(), Configuration: Append([][]byte{ @@ -121,14 +126,14 @@ var CDCHID = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointIN(EndpointEP1, TransferTypeInterrupt, 0x10, 0x10).Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointOUT(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), + EndpointIN(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), InterfaceHID.Bytes(), ClassHID.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), + EndpointIN(EndpointEP3, TransferTypeInterrupt, 0x40, 0x01).Bytes(), + EndpointOUT(EndpointEP3, TransferTypeInterrupt, 0x40, 0x01).Bytes(), }), HID: map[uint16][]byte{ 2: Append([][]byte{ // Update ClassLength in classHID whenever the array length is modified! diff --git a/src/machine/usb/descriptor/joystick.go b/src/machine/usb/descriptor/joystick.go index 65756e0d63..725c3efa64 100644 --- a/src/machine/usb/descriptor/joystick.go +++ b/src/machine/usb/descriptor/joystick.go @@ -121,6 +121,11 @@ var JoystickDefaultHIDReport = Append([][]byte{ // CDCJoystick requires that you append the JoystickDescriptor // to the Configuration before using. This is in order to support // custom configurations. +// EP1 IN : CDC Call Management +// EP2 OUT: CDC OUT +// EP2 IN : CDC IN +// EP3 OUT: HID OUT +// EP3 IN : HID IN var CDCJoystick = Descriptor{ Device: DeviceJoystick.Bytes(), Configuration: Append([][]byte{ @@ -131,14 +136,14 @@ var CDCJoystick = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointIN(EndpointEP1, TransferTypeInterrupt, 0x10, 0x10).Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointOUT(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), + EndpointIN(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), InterfaceHIDJoystick.Bytes(), ClassHIDJoystick.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), + EndpointIN(EndpointEP3, TransferTypeInterrupt, 0x40, 0x01).Bytes(), + EndpointOUT(EndpointEP3, TransferTypeInterrupt, 0x40, 0x01).Bytes(), }), HID: map[uint16][]byte{}, } diff --git a/src/machine/usb/descriptor/midi.go b/src/machine/usb/descriptor/midi.go index fad81f31d5..6524e05787 100644 --- a/src/machine/usb/descriptor/midi.go +++ b/src/machine/usb/descriptor/midi.go @@ -171,10 +171,10 @@ var ClassSpecificMIDIInEndpoint = ClassSpecificType{ const endpointMIDITypeLen = 9 -var endpointEP6IN = [endpointMIDITypeLen]byte{ +var endpointMIDIIN = [endpointMIDITypeLen]byte{ endpointMIDITypeLen, TypeEndpoint, - 0x86, // EndpointAddress + 0x83, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH @@ -183,14 +183,14 @@ var endpointEP6IN = [endpointMIDITypeLen]byte{ 0x00, // sync address } -var EndpointEP6IN = EndpointType{ - data: endpointEP6IN[:], +var EndpointMIDIIN = EndpointType{ + data: endpointMIDIIN[:], } -var endpointEP7OUT = [endpointMIDITypeLen]byte{ +var endpointMIDIOUT = [endpointMIDITypeLen]byte{ endpointMIDITypeLen, TypeEndpoint, - 0x07, // EndpointAddress + 0x03, // EndpointAddress 0x02, // Attributes 0x40, // MaxPacketSizeL 0x00, // MaxPacketSizeH @@ -199,8 +199,8 @@ var endpointEP7OUT = [endpointMIDITypeLen]byte{ 0x00, // sync address } -var EndpointEP7OUT = EndpointType{ - data: endpointEP7OUT[:], +var EndpointMIDIOUT = EndpointType{ + data: endpointMIDIOUT[:], } var configurationCDCMIDI = [configurationTypeLen]byte{ @@ -218,6 +218,11 @@ var ConfigurationCDCMIDI = ConfigurationType{ data: configurationCDCMIDI[:], } +// EP1 IN : CDC Call Management +// EP2 OUT: CDC OUT +// EP2 IN : CDC IN +// EP3 OUT: MIDI OUT (custom endpoint descriptor) +// EP3 IN : MIDI IN (custom endpoint descriptor) var CDCMIDI = Descriptor{ Device: DeviceCDC.Bytes(), Configuration: Append([][]byte{ @@ -228,10 +233,10 @@ var CDCMIDI = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointIN(EndpointEP1, TransferTypeInterrupt, 0x10, 0x10).Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointOUT(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), + EndpointIN(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), InterfaceAssociationMIDI.Bytes(), InterfaceAudio.Bytes(), ClassSpecificAudioInterface.Bytes(), @@ -241,9 +246,9 @@ var CDCMIDI = Descriptor{ ClassSpecificMIDIInJack2.Bytes(), ClassSpecificMIDIOutJack1.Bytes(), ClassSpecificMIDIOutJack2.Bytes(), - EndpointEP7OUT.Bytes(), + EndpointMIDIOUT.Bytes(), ClassSpecificMIDIOutEndpoint.Bytes(), - EndpointEP6IN.Bytes(), + EndpointMIDIIN.Bytes(), ClassSpecificMIDIInEndpoint.Bytes(), }), } diff --git a/src/machine/usb/descriptor/msc.go b/src/machine/usb/descriptor/msc.go index 55c6ddd857..42e0088b93 100644 --- a/src/machine/usb/descriptor/msc.go +++ b/src/machine/usb/descriptor/msc.go @@ -52,7 +52,17 @@ var ConfigurationMSC = ConfigurationType{ data: configurationMSC[:], } +var ( + EndpointMSCIN = EndpointIN(EndpointEP3, TransferTypeBulk, 0x40, 0x00) + EndpointMSCOUT = EndpointOUT(EndpointEP3, TransferTypeBulk, 0x40, 0x00) +) + // Mass Storage Class +// EP1 IN : CDC Call Management +// EP2 OUT: CDC OUT +// EP2 IN : CDC IN +// EP3 OUT: MSC OUT +// EP3 IN : MSC IN var MSC = Descriptor{ Device: DeviceCDC.Bytes(), Configuration: Append([][]byte{ @@ -63,10 +73,10 @@ var MSC = Descriptor{ ClassSpecificCDCACM.Bytes(), ClassSpecificCDCUnion.Bytes(), ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), + EndpointIN(EndpointEP1, TransferTypeInterrupt, 0x10, 0x10).Bytes(), InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), + EndpointOUT(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), + EndpointIN(EndpointEP2, TransferTypeBulk, 0x40, 0x00).Bytes(), InterfaceAssociationMSC.Bytes(), InterfaceMSC.Bytes(), EndpointMSCIN.Bytes(), diff --git a/src/machine/usb/msc/msc.go b/src/machine/usb/msc/msc.go index 420a06ed98..cc46dc6695 100644 --- a/src/machine/usb/msc/msc.go +++ b/src/machine/usb/msc/msc.go @@ -166,6 +166,7 @@ func (m *msc) sendCSW(status csw.Status) { } m.cbw.CSW(status, residue, m.cswBuf) m.state = mscStateStatusSent + m.queuedBytes = csw.MsgLen m.sendUSBPacket(m.cswBuf) } @@ -235,9 +236,9 @@ func (m *msc) run(b []byte, isEpOut bool) bool { // 6.6.1 CBW Not Valid // https://usb.org/sites/default/files/usbmassbulk_10.pdf m.state = mscStateNeedReset - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) - m.stallEndpoint(usb.CONTROL_ENDPOINT) + m.stallEndpointIn(usb.MSC_ENDPOINT_IN) + m.stallEndpointOut(usb.MSC_ENDPOINT_OUT) + m.stallEndpointIn(usb.CONTROL_ENDPOINT) return ack } @@ -284,7 +285,7 @@ func (m *msc) run(b []byte, isEpOut bool) bool { if m.state == mscStateStatus && !m.txStalled { if m.cbw.transferLength() > m.sentBytes && m.cbw.isIn() { // 6.7.2 The Thirteen Cases - Case 5 (Hi > Di): STALL before status - m.stallEndpoint(usb.MSC_ENDPOINT_IN) + m.stallEndpointIn(usb.MSC_ENDPOINT_IN) } else if m.sendZLP { // Send a zero-length packet to force the end of the transfer before we send a CSW m.queuedBytes = 0 diff --git a/src/machine/usb/msc/scsi.go b/src/machine/usb/msc/scsi.go index 4cec23e2f2..562a718eaf 100644 --- a/src/machine/usb/msc/scsi.go +++ b/src/machine/usb/msc/scsi.go @@ -298,9 +298,9 @@ func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCo if expected > 0 && residue > 0 { if m.cbw.isIn() { - m.stallEndpoint(usb.MSC_ENDPOINT_IN) + m.stallEndpointIn(usb.MSC_ENDPOINT_IN) } else { - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) + m.stallEndpointOut(usb.MSC_ENDPOINT_OUT) } } } diff --git a/src/machine/usb/msc/setup.go b/src/machine/usb/msc/setup.go index 00507aac69..fb4aaf2c2a 100644 --- a/src/machine/usb/msc/setup.go +++ b/src/machine/usb/msc/setup.go @@ -52,32 +52,30 @@ func (m *msc) handleClearFeature(setup usb.Setup, wValue uint16) bool { // (c) a Clear Feature HALT to the Bulk-Out endpoint (clear stall OUT) // https://usb.org/sites/default/files/usbmassbulk_10.pdf if m.state == mscStateNeedReset { - wIndex := setup.WIndex & 0x7F // Clear the direction bit from the endpoint address for comparison + wIndex := uint8(setup.WIndex & 0x7F) if wIndex == usb.MSC_ENDPOINT_IN { - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - } else if wIndex == usb.MSC_ENDPOINT_OUT { - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) + if (setup.WIndex & 0x80) != 0 { + m.stallEndpointIn(wIndex) + } else { + m.stallEndpointOut(wIndex) + } } machine.SendZlp() return true } - // Clear the direction bit from the endpoint address for comparison - wIndex := setup.WIndex & 0x7F - - // Clear the IN/OUT stalls if addressed to the endpoint + wIndex := uint8(setup.WIndex & 0x7F) if wIndex == usb.MSC_ENDPOINT_IN { - m.clearStallEndpoint(usb.MSC_ENDPOINT_IN) - ok = true - } - if wIndex == usb.MSC_ENDPOINT_OUT { - m.clearStallEndpoint(usb.MSC_ENDPOINT_OUT) - ok = true - } - // Send a CSW if needed to resume after the IN endpoint stall is cleared - if m.state == mscStateStatus && wIndex == usb.MSC_ENDPOINT_IN { - m.sendCSW(m.respStatus) - ok = true + if (setup.WIndex & 0x80) != 0 { + m.clearStallEndpointIn(wIndex) + ok = true + if m.state == mscStateStatus { + m.sendCSW(m.respStatus) + } + } else { + m.clearStallEndpointOut(wIndex) + ok = true + } } if ok { @@ -120,26 +118,28 @@ func (m *msc) handleReset(setup usb.Setup, wValue uint16) bool { return true } -func (m *msc) stallEndpoint(ep uint8) { - if ep == usb.MSC_ENDPOINT_IN { - m.txStalled = true - machine.USBDev.SetStallEPIn(usb.MSC_ENDPOINT_IN) - } else if ep == usb.MSC_ENDPOINT_OUT { - m.rxStalled = true - machine.USBDev.SetStallEPOut(usb.MSC_ENDPOINT_OUT) - } else if ep == usb.CONTROL_ENDPOINT { +func (m *msc) stallEndpointIn(ep uint8) { + if ep == usb.CONTROL_ENDPOINT { machine.USBDev.SetStallEPIn(usb.CONTROL_ENDPOINT) + return } + m.txStalled = true + machine.USBDev.SetStallEPIn(uint32(ep)) } -func (m *msc) clearStallEndpoint(ep uint8) { - if ep == usb.MSC_ENDPOINT_IN { - machine.USBDev.ClearStallEPIn(usb.MSC_ENDPOINT_IN) - m.txStalled = false - } else if ep == usb.MSC_ENDPOINT_OUT { - machine.USBDev.ClearStallEPOut(usb.MSC_ENDPOINT_OUT) - m.rxStalled = false - } +func (m *msc) stallEndpointOut(ep uint8) { + m.rxStalled = true + machine.USBDev.SetStallEPOut(uint32(ep)) +} + +func (m *msc) clearStallEndpointIn(ep uint8) { + machine.USBDev.ClearStallEPIn(uint32(ep)) + m.txStalled = false +} + +func (m *msc) clearStallEndpointOut(ep uint8) { + machine.USBDev.ClearStallEPOut(uint32(ep)) + m.rxStalled = false } func (m *msc) setStringField(field []byte, value string) { diff --git a/src/machine/usb/usb.go b/src/machine/usb/usb.go index 40983a9a3c..1d2dad4352 100644 --- a/src/machine/usb/usb.go +++ b/src/machine/usb/usb.go @@ -74,13 +74,13 @@ const ( CONTROL_ENDPOINT = 0 CDC_ENDPOINT_ACM = 1 CDC_ENDPOINT_OUT = 2 - CDC_ENDPOINT_IN = 3 - HID_ENDPOINT_IN = 4 // for Interrupt In - HID_ENDPOINT_OUT = 5 // for Interrupt Out - MIDI_ENDPOINT_IN = 6 // for Bulk In - MIDI_ENDPOINT_OUT = 7 // for Bulk Out - MSC_ENDPOINT_IN = 6 // for Bulk In - MSC_ENDPOINT_OUT = 7 // for Bulk Out + CDC_ENDPOINT_IN = 2 + HID_ENDPOINT_IN = 3 // for Interrupt In + HID_ENDPOINT_OUT = 3 // for Interrupt Out + MIDI_ENDPOINT_IN = 3 // for Bulk In + MIDI_ENDPOINT_OUT = 3 // for Bulk Out + MSC_ENDPOINT_IN = 3 // for Bulk In + MSC_ENDPOINT_OUT = 3 // for Bulk Out // bmRequestType REQUEST_HOSTTODEVICE = 0x00