1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 using Antmicro.Renode.Core.Structure;
15 using System.Linq;
16 using Antmicro.Renode.Utilities.Collections;
17 using Antmicro.Renode.Utilities.Packets;
18 using Antmicro.Renode.Core.USB;
19 
20 namespace Antmicro.Renode.Peripherals.USB
21 {
22     public class MPFS_USB : SimpleContainer<IUSBDevice>, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IProvidesRegisterCollection<WordRegisterCollection>, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize
23     {
MPFS_USB(IMachine machine, ControllerMode mode = ControllerMode.Host)24         public MPFS_USB(IMachine machine, ControllerMode mode = ControllerMode.Host) : base(machine)
25         {
26             this.mode = mode;
27 
28             addressToDeviceCache = new TwoWayDictionary<byte, IUSBDevice>();
29 
30             fifoFromDeviceToHost = new Queue<byte>[NumberOfEndpoints];
31             fifoFromHostToDevice = new Queue<byte>[NumberOfEndpoints];
32             receiveDeviceAddress = new IValueRegisterField[NumberOfEndpoints];
33             transmitDeviceAddress = new IValueRegisterField[NumberOfEndpoints];
34             requestInTransaction = new IFlagRegisterField[NumberOfEndpoints];
35             transmitTargetEndpointNumber = new IValueRegisterField[NumberOfEndpoints];
36             receiveTargetEndpointNumber = new IValueRegisterField[NumberOfEndpoints];
37 
38             for(var i = 0; i < NumberOfEndpoints; i++)
39             {
40                 fifoFromDeviceToHost[i] = new Queue<byte>();
41                 fifoFromHostToDevice[i] = new Queue<byte>();
42             }
43 
44             MainIRQ = new GPIO();
45             DmaIRQ = new GPIO();
46 
47             byteRegisters = new ByteRegisterCollection(this);
48             wordRegisters = new WordRegisterCollection(this);
49             doubleWordRegisters = new DoubleWordRegisterCollection(this);
50 
51             var gate = new GPIOGate(MainIRQ);
52             usbInterruptsManager = new InterruptManager<UsbInterrupt>(this, gate.GetGPIO(), "main");
53             txInterruptsManager = new InterruptManager<TxInterrupt>(this, gate.GetGPIO(), "main");
54             rxInterruptsManager = new InterruptManager<RxInterrupt>(this, gate.GetGPIO(), "main");
55 
56             DefineCommonRegisters();
57             DefineIndexedRegisters();
58             DefineFifoRegisters();
59             DefineControlAndStatusRegisters();
60             DefineNonIndexedEndpointControlAndStatusRegisters();
61             DefineMultipointControlAndStatusRegisters();
62 
63             ResetInterrupts();
64         }
65 
Reset()66         public override void Reset()
67         {
68             byteRegisters.Reset();
69             wordRegisters.Reset();
70             doubleWordRegisters.Reset();
71             ResetInterrupts();
72         }
73 
ReadByte(long offset)74         public byte ReadByte(long offset)
75         {
76             if(!byteRegisters.TryRead(offset, out var res))
77             {
78                 this.LogUnhandledRead(offset);
79             }
80             return res;
81         }
82 
WriteByte(long offset, byte value)83         public void WriteByte(long offset, byte value)
84         {
85             byteRegisters.Write(offset, value);
86         }
87 
ReadWord(long offset)88         public ushort ReadWord(long offset)
89         {
90             if(!wordRegisters.TryRead(offset, out var res))
91             {
92                 this.LogUnhandledRead(offset);
93             }
94             return res;
95         }
96 
WriteWord(long offset, ushort value)97         public void WriteWord(long offset, ushort value)
98         {
99             wordRegisters.Write(offset, value);
100         }
101 
ReadDoubleWord(long offset)102         public uint ReadDoubleWord(long offset)
103         {
104             if(!doubleWordRegisters.TryRead(offset, out var res))
105             {
106                 this.LogUnhandledRead(offset);
107             }
108             return res;
109         }
110 
WriteDoubleWord(long offset, uint value)111         public void WriteDoubleWord(long offset, uint value)
112         {
113             doubleWordRegisters.Write(offset, value);
114         }
115 
Register(IUSBDevice peripheral, NumberRegistrationPoint<int> registrationPoint)116         public override void Register(IUSBDevice peripheral, NumberRegistrationPoint<int> registrationPoint)
117         {
118             // when a new device is attached to the controller it is not automatically started, but waits for reset;
119             // if there are multiple devices attached they are reset by the controller one at a time -
120             // it ensures that there is only one device with address 0 (the default one) at the bus;
121             base.Register(peripheral, registrationPoint);
122             TryInitializeConnectedDevice();
123         }
124 
Unregister(IUSBDevice peripheral)125         public override void Unregister(IUSBDevice peripheral)
126         {
127             base.Unregister(peripheral);
128             if(sessionInProgress.Value)
129             {
130                 usbInterruptsManager.SetInterrupt(UsbInterrupt.DeviceDisconnectedSessionEnded);
131             }
132         }
133 
134         [IrqProvider]
135         public GPIO MainIRQ { get; private set; }
136         public GPIO DmaIRQ { get; private set; }
137 
138         public long Size => 0x1000;
139 
140         ByteRegisterCollection IProvidesRegisterCollection<ByteRegisterCollection>.RegistersCollection => byteRegisters;
141 
142         WordRegisterCollection IProvidesRegisterCollection<WordRegisterCollection>.RegistersCollection => wordRegisters;
143 
144         DoubleWordRegisterCollection IProvidesRegisterCollection<DoubleWordRegisterCollection>.RegistersCollection => doubleWordRegisters;
145 
146         private bool ReadAndClearInterrupt<T>(InterruptManager<T> irqManager, T irq) where T : struct, IConvertible
147         {
148             var result = irqManager.IsSet(irq);
149             if(result)
150             {
151                 irqManager.SetInterrupt(irq, false);
152             }
153             return result;
154         }
155 
DefineCommonRegisters()156         private void DefineCommonRegisters()
157         {
158             Registers.FunctionAddress.Tag8(this, name: "FADDR_REG")
159             ;
160 
161             Registers.Power.Define8(this, 0x20, name: "POWER_REG")
162                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => true, name: "HS Mode")
163             ;
164 
165             Registers.TransmitInterruptsStatus
166                 .Bind(this, txInterruptsManager.GetRegister<WordRegister>((irq, _) => ReadAndClearInterrupt(txInterruptsManager, irq)), name: "TX_IRQ_REG")
167             ;
168 
169             Registers.ReceiveInterruptsStatus
170                 .Bind(this, rxInterruptsManager.GetRegister<WordRegister>((irq, _) => ReadAndClearInterrupt(rxInterruptsManager, irq)), name: "RX_IRQ_REG")
171             ;
172 
173             Registers.TransmitInterruptsEnable
174                 .Bind(this, txInterruptsManager.GetInterruptEnableRegister<WordRegister>(), name: "TX_IRQ_EN_REG")
175             ;
176 
177             Registers.ReceiveInterrptsEnable
178                 .Bind(this, rxInterruptsManager.GetInterruptEnableRegister<WordRegister>(), name: "RX_IRQ_EN_REG")
179             ;
180 
181             Registers.UsbInterruptsStatus
182                 .Bind(this, usbInterruptsManager.GetRegister<ByteRegister>((irq, _) => ReadAndClearInterrupt(usbInterruptsManager, irq)), name: "USB_IRQ_REG")
183             ;
184 
185             Registers.UsbInterruptsEnable
186                 .Bind(this, usbInterruptsManager.GetInterruptEnableRegister<ByteRegister>(), name: "USB_IRQ_EN_REG")
187             ;
188 
189             Registers.Frame.Tag16(this, name: "FRAME_REG")
190             ;
191 
192             Registers.Index.Define8(this, name: "INDEX_REG")
193                 .WithValueField(0, 4, out index, name: "Selected Endpoint")
194             ;
195 
196             Registers.TestMode.Tag8(this, name: "TEST_MODE_REG")
197             ;
198         }
199 
DefineIndexedRegisters()200         private void DefineIndexedRegisters()
201         {
202             Registers.TransmitMaximumPacketSize.Tag16(this, name: "TX_MAX_P_REG")
203             ;
204 
205             // !WARNING driver treats those Low/High as one short register, docs splits it into two byte ones
206             if(mode == ControllerMode.Host)
207             {
208                 // !WARNING those two registers are mutually exclusive and their accessability depends on INDEX_REG value
209                 HostRegisters.Endpoint0ControlStatusLow.Tag8(this, name: "CSR0L_REG")
210                 ;
211                 HostRegisters.EndpointNTransmitControlStatusLow.Tag8(this, name: "TX_CSRL_REG")
212                 ;
213 
214                 // !WARNING those two registers are mutually exclusive and their accessability depends on INDEX_REG value
215                 HostRegisters.Endpoint0ControlStatusHigh.Tag8(this, name: "CSR0H_REG")
216                 ;
217                 HostRegisters.EndpointNTransmitControlStatusHigh.Tag8(this, name: "TX_CSRH_REG")
218                 ;
219             }
220             else
221             {
222                 // !WARNING those two registers are mutually exclusive and their accessability depends on INDEX_REG value
223                 DeviceRegisters.Endpoint0ControlStatusLow.Tag8(this, name: "CSR0L_REG")
224                 ;
225                 DeviceRegisters.EndpointNTransmitControlStatusLow.Tag8(this, name: "TX_CSRL_REG")
226                 ;
227 
228                 // !WARNING those two registers are mutually exclusive and their accessability depends on INDEX_REG value
229                 DeviceRegisters.Endpoint0ControlStatusHigh.Tag8(this, name: "CSR0H_REG")
230                 ;
231                 DeviceRegisters.EndpointNTransmitControlStatusHigh.Tag8(this, name: "TX_CSRH_REG")
232                 ;
233             }
234 
235             Registers.ReceiveMaximumPacketSize.Tag16(this, name: "RX_MAX_P_REG")
236             ;
237 
238             // !WARNING driver treats those Low/High as one short register, docs splits it into two byte ones
239             if(mode == ControllerMode.Host)
240             {
241                 HostRegisters.ReceiveControlStatusLow.Tag8(this, name: "RX_CSRL_REG")
242                 ;
243 
244                 HostRegisters.ReceiveControlStatusHigh.Tag8(this, name: "RX_CSRH_REG")
245                 ;
246             }
247             else
248             {
249                 DeviceRegisters.ReceiveControlStatusLow.Tag8(this, name: "RX_CSRL_REG")
250                 ;
251 
252                 DeviceRegisters.ReceiveControlStatusHigh.Tag8(this, name: "RX_CSRH_REG")
253                 ;
254             }
255 
256             // !SIMPLIFICATION those are two different registers in the documentation, but I implement them the same way for now
257             Registers.Endpoint0FifoCount.Tag8(this, name: "COUNT0_REG")
258             ;
259             Registers.EndpointNReceiveFifoCount.Define16(this)
260                 .WithValueField(0, 14, FieldMode.Read, valueProviderCallback: _ => (byte)fifoFromDeviceToHost[index.Value].Count);
261 
262             Registers.Endpoint0Type.Tag8(this, name: "TYPE0_REG")
263             ;
264             Registers.EndpointNTransmitType.Tag8(this, name: "TX_TYPE_REG")
265             ;
266 
267             Registers.Endpoint0NAKLimit.Tag8(this, name: "NAK_LIMIT0_REG")
268             ;
269             Registers.EndpointNTransmitInterval.Tag8(this, name: "TX_INTERVAL_REG")
270             ;
271 
272             Registers.EndpointNReceiveType.Tag8(this, name: "RX_TYPE_REG")
273             ;
274 
275             Registers.EndpointNReceiveInterval.Tag8(this, name: "RX_INTERVAL_REG")
276             ;
277 
278             Registers.Endpoint0ConfigData.Tag8(this, name: "CONFIG_DATA_REG")
279             ;
280             Registers.EndpointNFifoSize.Tag8(this, name: "FIFO_SIZE_REG")
281             ;
282         }
283 
ReadFromFifo(int fifoId, int numberOfBytes)284         private ulong ReadFromFifo(int fifoId, int numberOfBytes)
285         {
286             var result = 0ul;
287             for(var i = 0; i < numberOfBytes; i++)
288             {
289                 result |= (ulong)((long)fifoFromDeviceToHost[fifoId].Dequeue() << (8 * i));
290             }
291             return result;
292         }
293 
WriteToFifo(int fifoId, int numberOfBytes, ulong value)294         private void WriteToFifo(int fifoId, int numberOfBytes, ulong value)
295         {
296             for(var i = 0; i < numberOfBytes; i++)
297             {
298                 fifoFromHostToDevice[fifoId].Enqueue((byte)(value >> (8 * i)));
299             }
300         }
301 
DefineFifoRegisters()302         private void DefineFifoRegisters()
303         {
304 
305             for(var i = 0; i < NumberOfEndpoints; i++)
306             {
307                 var fifoId = i;
308 
309                 ((Registers)(Registers.Endpoint0Fifo + fifoId * 4)).Define32(this, name: $"EP{fifoId}_FIFO_REG")
310                     .WithValueField(0, 32,
311                         writeCallback: (_, val) => WriteToFifo(fifoId, 4, val),
312                         valueProviderCallback: _ => (uint)ReadFromFifo(fifoId, 4))
313                 ;
314 
315                 ((Registers)(Registers.Endpoint0Fifo + fifoId * 4)).Define16(this, name: $"EP{fifoId}_FIFO_REG")
316                     .WithValueField(0, 16,
317                         writeCallback: (_, val) => WriteToFifo(fifoId, 2, val),
318                         valueProviderCallback: _ => (ushort)ReadFromFifo(fifoId, 2))
319                 ;
320 
321                 ((Registers)(Registers.Endpoint0Fifo + fifoId * 4)).Define8(this, name: $"EP{fifoId}_FIFO_REG")
322                     .WithValueField(0, 8,
323                         writeCallback: (_, val) => WriteToFifo(fifoId, 1, val),
324                         valueProviderCallback: _ => (byte)ReadFromFifo(fifoId, 1))
325                 ;
326             }
327         }
328 
HandleSessionStart()329         private void HandleSessionStart()
330         {
331             lock(addressToDeviceCache)
332             {
333                 addressToDeviceCache.Clear();
334                 if(sessionInProgress.Value)
335                 {
336                     TryInitializeConnectedDevice();
337                 }
338             }
339         }
340 
DefineControlAndStatusRegisters()341         private void DefineControlAndStatusRegisters()
342         {
343 
344             Registers.DeviceControl.Define8(this, 0x80, name: "DEV_CTRL_REG")
345                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "B-Device")
346                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => true, name: "FSDev")
347                 .WithEnumField<ByteRegister, VBusLevel>(3, 2, FieldMode.Read, valueProviderCallback: _ => VBusLevel.AboveVBusValid, name: "VBus")
348                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => mode == ControllerMode.Host, name: "Host Mode")
349                 .WithFlag(0, out sessionInProgress, changeCallback: (_, val) => HandleSessionStart(), name: "Session")
350             ;
351         }
352 
DefineNonIndexedEndpointControlAndStatusRegisters()353         private void DefineNonIndexedEndpointControlAndStatusRegisters()
354         {
355             Registers.Endpoint0TransmitControlStatus.Define16(this, name: $"EP0_TX_CSR_REG")
356                 .WithFlag(0, out var receivedPacketReady, name: "RxPktRdy")
357                 .WithFlag(1, out var transmitPacketReady,  name: "TxPktRdy")
358                 .WithFlag(3, out var setupPacket, name: "SetupPkt")
359                 .WithFlag(5, out var requestPacket, name: "ReqPkt")
360                 .WithFlag(6, out var statusPacket, name: "StatusPkt")
361                 .WithWriteCallback((_, __) =>
362                 {
363                     if(transmitPacketReady.Value)
364                     {
365                         transmitPacketReady.Value = false;
366                         if(!TryGetDeviceForEndpoint(0, Direction.HostToDevice, out var peripheral))
367                         {
368                             this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint 0 in host to device direction");
369                             return;
370                         }
371 
372                         if(setupPacket.Value)
373                         {
374                             setupPacket.Value = false;
375                             var data = fifoFromHostToDevice[0].DequeueAll();
376                             if(data.Length != 8)
377                             {
378                                 this.Log(LogLevel.Warning, "Setup packet must be composed of 8 bytes, but there are currently {0} in the buffer. Refusing to send packet and dropping buffered data.", data.Length);
379                                 return;
380                             }
381 
382                             var packet = Packet.Decode<SetupPacket>(data);
383                             peripheral.USBCore.HandleSetupPacket(packet, receivedBytes =>
384                             {
385                                 fifoFromDeviceToHost[0].EnqueueRange(receivedBytes);
386                                 txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0);
387                             });
388                         }
389 
390                         if(statusPacket.Value)
391                         {
392                             statusPacket.Value = false;
393                             // nothing happens here - just setting the interrupt
394                             txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0);
395                         }
396                     }
397 
398                     if(requestPacket.Value)
399                     {
400                         requestPacket.Value = false;
401 
402                         // since the communication with the device is instantenous the data should already wait in the buffer
403                         receivedPacketReady.Value = true;
404                         txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0);
405                     }
406                 })
407             ;
408 
409             ((Registers)Registers.Endpoint0ReceivePacketSize).Define8(this, name: $"EP0_RX_COUNT_REG")
410                 .WithValueField(0, 8, FieldMode.Read, name: $"EP0_RX_COUNT_REG", valueProviderCallback: _ =>
411                 {
412                     return checked((byte)fifoFromDeviceToHost[0].Count);
413                 })
414             ;
415 
416             for(var i = 1; i < NumberOfEndpoints; i++)
417             {
418                 var endpointId = i;
419                 IFlagRegisterField localReceivedPacketReady = null;
420 
421                 ((Registers)(Registers.Endpoint0ReceiveControlStatus + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_RX_CSR_REG")
422                     .WithFlag(5, out requestInTransaction[endpointId], name: "ReqPkt",
423                         writeCallback: (_, val) =>
424                         {
425                             if(!val)
426                             {
427                                 return;
428                             }
429 
430                             if(!TryGetDeviceForEndpoint(endpointId, Direction.DeviceToHost, out var peripheral))
431                             {
432                                 this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint {0} in device to host direction", endpointId);
433                                 return;
434                             }
435 
436                             var endpoint = peripheral.USBCore.GetEndpoint((int)receiveTargetEndpointNumber[endpointId].Value, Direction.DeviceToHost);
437                             if(endpoint == null)
438                             {
439                                 this.Log(LogLevel.Warning, "Trying to read from a non-existing endpoint #{0}", receiveTargetEndpointNumber[endpointId].Value);
440                                 return;
441                             }
442 
443                             endpoint.SetDataReadCallbackOneShot((e, bytes) =>
444                             {
445                                 fifoFromDeviceToHost[endpointId].EnqueueRange(bytes);
446                                 requestInTransaction[endpointId].Value = false;
447                                 localReceivedPacketReady.Value = true;
448                                 rxInterruptsManager.SetInterrupt((RxInterrupt)endpointId);
449                             });
450                         })
451                     .WithFlag(4, FieldMode.WriteOneToClear, name: "FlushFIFO", writeCallback: (_, val) =>
452                     {
453                         if(!val)
454                         {
455                             return;
456                         }
457 
458                         fifoFromDeviceToHost[endpointId].Clear();
459                         localReceivedPacketReady.Value = false;
460                     })
461                     .WithFlag(0, out localReceivedPacketReady, name: "RxPktRdy")
462                 ;
463 
464                 ((Registers)(Registers.Endpoint0ReceivePacketSize + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_RX_COUNT_REG")
465                     .WithValueField(0, 14, FieldMode.Read, name: $"EP{endpointId}_RX_COUNT_REG", valueProviderCallback: _ =>
466                     {
467                         return checked((uint)fifoFromDeviceToHost[endpointId].Count);
468                     })
469                 ;
470 
471                 ((Registers)(Registers.Endpoint0TransmitControlStatus + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_TX_CSR_REG")
472                     .WithTag("NAK Timeout/IncompTx", 7, 1)
473                     .WithTag("ClrDataTog", 6, 1)
474                     .WithTag("RxStall", 5, 1)
475                     .WithFlag(4, out var setupPkt, FieldMode.Read | FieldMode.Set, name: "SetupPkt")
476                     .WithTag("FlushFIFO", 3, 1)
477                     .WithTag("Error", 2, 1)
478                     .WithFlag(1, FieldMode.Read, name: "FIFONotEmpty", valueProviderCallback: _ => fifoFromHostToDevice[endpointId].Count > 0)
479                     .WithFlag(0, out var txPktRdy, FieldMode.Read | FieldMode.Set, name: "TxPktRdy")
480                     .WithWriteCallback((_, val) =>
481                     {
482                         if(!txPktRdy.Value)
483                         {
484                             return;
485                         }
486 
487                         if(setupPkt.Value)
488                         {
489                             throw new ArgumentException("Setup packets on Endpoint 1-4 are not supported");
490                         }
491                         else
492                         {
493                             // standard OUT packet
494                             if(!TryGetDeviceForEndpoint(endpointId, Direction.HostToDevice, out var peripheral))
495                             {
496                                 this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint {0} in host to device direction", endpointId);
497                                 return;
498                             }
499 
500                             var mappedEndpointId = (int)transmitTargetEndpointNumber[endpointId].Value;
501                             var endpoint = peripheral.USBCore.GetEndpoint(mappedEndpointId, Direction.HostToDevice);
502                             if(endpoint == null)
503                             {
504                                 this.Log(LogLevel.Warning, "Trying to write to a non-existing endpoint #{0}", mappedEndpointId);
505                             }
506 
507                             var data = fifoFromHostToDevice[endpointId].DequeueAll();
508                             endpoint.WriteData(data);
509 
510                             txPktRdy.Value = false;
511                             txInterruptsManager.SetInterrupt((TxInterrupt)endpointId);
512                         }
513                     })
514                 ;
515 
516                 ((Registers)Registers.Endpoint0TransmitType + endpointId * 0x10).Define8(this, name: $"EP{endpointId}_TX_TYPE_REG")
517                     .WithTag("Speed", 6, 2)
518                     .WithTag("Protocol", 4, 2)
519                     .WithValueField(0, 4, out transmitTargetEndpointNumber[endpointId], name: "Target Endpoint Number")
520                 ;
521 
522                 ((Registers)Registers.Endpoint0ReceiveType + endpointId * 0x10).Define8(this, name: $"EP{endpointId}_RX_TYPE_REG")
523                     .WithTag("Speed", 6, 2)
524                     .WithTag("Protocol", 4, 2)
525                     .WithValueField(0, 4, out receiveTargetEndpointNumber[endpointId], name: "Target Endpoint Number")
526                 ;
527             }
528         }
529 
DefineMultipointControlAndStatusRegisters()530         private void DefineMultipointControlAndStatusRegisters()
531         {
532             for(var i = 0; i < NumberOfEndpoints; i++)
533             {
534                 var endpointId = i;
535 
536                 ((Registers)(Registers.Endpoint0TransmitFunctionAddress + endpointId * 0x8)).Define8(this, name: $"EP{endpointId}_TX_FUNC_ADDR_REG")
537                     .WithValueField(0, 7, out transmitDeviceAddress[endpointId], name: "TxFuncAddr")
538                 ;
539 
540                 ((Registers)(Registers.Endpoint0ReceiveFunctionAddress + endpointId * 0x8)).Define8(this, name: $"EP{endpointId}_RX_FUNC_ADDR_REG")
541                     .WithValueField(0, 7, out receiveDeviceAddress[endpointId], name: "RxFuncAddr")
542                 ;
543             }
544         }
545 
ResetInterrupts()546         private void ResetInterrupts()
547         {
548             usbInterruptsManager.Reset();
549             txInterruptsManager.Reset();
550             rxInterruptsManager.Reset();
551         }
552 
TryGetDeviceForEndpoint(int endpointId, Direction direction, out IUSBDevice device)553         private bool TryGetDeviceForEndpoint(int endpointId, Direction direction, out IUSBDevice device)
554         {
555             IValueRegisterField addressField = null;
556             switch(direction)
557             {
558                 case Direction.DeviceToHost:
559                     addressField = receiveDeviceAddress[endpointId];
560                     break;
561                 case Direction.HostToDevice:
562                     addressField = transmitDeviceAddress[endpointId];
563                     break;
564                 default:
565                     throw new ArgumentException($"Unexpected direction: {direction}");
566             }
567 
568             lock(addressToDeviceCache)
569             {
570                 var address = (byte)addressField.Value;
571                 if(!addressToDeviceCache.TryGetValue(address, out device))
572                 {
573                     // it will happen at the first access to the device after it has been granted an address
574                     device = this.ChildCollection.Select(x => x.Value).FirstOrDefault(x => x.USBCore.Address == address);
575                     if(device != null)
576                     {
577                         if(!addressToDeviceCache.TryExchange(device, address, out var oldAddress) || oldAddress != 0)
578                         {
579                             this.Log(LogLevel.Error, "USB device address change detected: previous address 0x{0:X}, current address 0x{1:X}. This might lead to problems", oldAddress, address);
580                         }
581 
582                         TryInitializeConnectedDevice();
583                     }
584                 }
585 
586                 if(device != null && device.USBCore.Address != address)
587                 {
588                     this.Log(LogLevel.Error, "USB device address change detected: previous address 0x{0:X}, current address 0x{1:X}. This might lead to problems", address, device.USBCore.Address);
589                 }
590                 return device != null;
591             }
592         }
593 
TryInitializeConnectedDevice()594         private bool TryInitializeConnectedDevice()
595         {
596             if(!sessionInProgress.Value)
597             {
598                 // we don't initialize devices when session is inactive
599                 return false;
600             }
601 
602             lock(addressToDeviceCache)
603             {
604                 if(addressToDeviceCache.Exists(0))
605                 {
606                     // there is an enumeration in progress, the next device will be picked automatically later
607                     return false;
608                 }
609 
610                 var peripheral = ChildCollection.Values.FirstOrDefault(x => !addressToDeviceCache.Exists(x));
611                 if(peripheral == null)
612                 {
613                     // no more devices to initialize
614                     return false;
615                 }
616 
617                 addressToDeviceCache.Add(0, peripheral);
618 
619                 usbInterruptsManager.SetInterrupt(UsbInterrupt.DeviceConnected);
620                 return true;
621             }
622         }
623 
624         private readonly TwoWayDictionary<byte, IUSBDevice> addressToDeviceCache;
625 
626         private IFlagRegisterField[] requestInTransaction = new IFlagRegisterField[NumberOfEndpoints];
627         private IValueRegisterField[] transmitDeviceAddress;
628         private IValueRegisterField[] receiveDeviceAddress;
629         private IValueRegisterField[] transmitTargetEndpointNumber;
630         private IValueRegisterField[] receiveTargetEndpointNumber;
631         private IValueRegisterField index;
632         private IFlagRegisterField sessionInProgress;
633         private readonly Queue<byte>[] fifoFromHostToDevice;
634         private readonly Queue<byte>[] fifoFromDeviceToHost;
635 
636         private readonly InterruptManager<UsbInterrupt> usbInterruptsManager;
637         private readonly InterruptManager<TxInterrupt> txInterruptsManager;
638         private readonly InterruptManager<RxInterrupt> rxInterruptsManager;
639 
640         private readonly ByteRegisterCollection byteRegisters;
641         private readonly WordRegisterCollection wordRegisters;
642         private readonly DoubleWordRegisterCollection doubleWordRegisters;
643 
644         // I couldn't find any mention of how to change mode by the software in the documentation.
645         private readonly ControllerMode mode;
646 
647         private const int NumberOfEndpoints = 5;
648 
649         public enum ControllerMode
650         {
651             Host,
652             Device
653         }
654 
655         private enum UsbInterrupt
656         {
657             Suspend = 0,
658             [EnabledOnReset] Resume = 1,
659             [EnabledOnReset] ResetBabble = 2,
660             StartOfFrame = 3,
661             DeviceConnected = 4,
662             DeviceDisconnectedSessionEnded = 5,
663             SessionRequest = 6,
664             VBusError = 7
665         }
666 
667         private enum TxInterrupt
668         {
669             [EnabledOnReset] Endpoint0 = 0,
670             [EnabledOnReset] Endpoint1 = 1,
671             [EnabledOnReset] Endpoint2 = 2,
672             [EnabledOnReset] Endpoint3 = 3,
673             [EnabledOnReset] Endpoint4 = 4
674         }
675 
676         private enum RxInterrupt
677         {
678             [EnabledOnReset] Endpoint1 = 1,
679             [EnabledOnReset] Endpoint2 = 2,
680             [EnabledOnReset] Endpoint3 = 3,
681             [EnabledOnReset] Endpoint4 = 4
682         }
683 
684         private enum Registers
685         {
686             FunctionAddress = 0x0,
687             Power = 0x1,
688             TransmitInterruptsStatus = 0x2,
689             ReceiveInterruptsStatus = 0x4,
690             TransmitInterruptsEnable = 0x6,
691             ReceiveInterrptsEnable = 0x8,
692             UsbInterruptsStatus = 0xA,
693             UsbInterruptsEnable = 0xB,
694             Frame = 0xC,
695             Index = 0xE,
696             TestMode = 0xF,
697 
698             TransmitMaximumPacketSize = 0x10,
699             // defined by the rest of registers
700             ReceiveMaximumPacketSize = 0x14,
701             // defined by the rest of registers
702 
703             Endpoint0FifoCount = 0x18,
704             EndpointNReceiveFifoCount = 0x18,
705 
706             Endpoint0Type = 0x1A,
707             EndpointNTransmitType = 0x1A,
708 
709             Endpoint0NAKLimit = 0x1B,
710             EndpointNTransmitInterval = 0x1B,
711 
712             EndpointNReceiveType = 0x1C,
713 
714             EndpointNReceiveInterval = 0x1D,
715 
716             Endpoint0ConfigData = 0x1F,
717             EndpointNFifoSize = 0x1F,
718 
719             // FIFO registers
720             Endpoint0Fifo = 0x20,
721             Endpoint1Fifo = 0x24,
722             Endpoint2Fifo = 0x28,
723             Endpoint3Fifo = 0x2C,
724             Endpoint4Fifo = 0x30,
725             //driver suggests that there are more fifo registers, but documentation says nothing about it
726 
727             DeviceControl = 0x60,
728             Misc = 0x61,
729             TransmitFifoSize = 0x62,
730             ReceiveFifoSize = 0x63,
731             TransmitFifoAddress = 0x64,
732             ReceiveFifoAddress = 0x66,
733             VbusControl = 0x68,
734             HwVersion = 0x6C,
735             // 2-bytes gap, intentionally
736 
737             UlpiVbysControl = 0x70,
738             UlpiCarKitControl = 0x71,
739             UlpiInterruptMask = 0x72,
740             UlpiInterruptSources = 0x73,
741             UlpiData = 0x74,
742             UlpiAddress = 0x75,
743             UlpiControl = 0x76,
744             UlpiRawData = 0x77,
745             EndpointInfo = 0x78,
746             RamInfo = 0x79,
747             LinkInfo = 0x7A,
748             VbusPulseLength = 0x7B,
749             HighSpeedEOF1 = 0x7C,
750             FullSpeedEOF1 = 0x7D,
751             LowSpeedEOF1 = 0x7E,
752             SoftReset = 0x7F,
753 
754             // Multipoint Control And Status Registers
755             Endpoint0TransmitFunctionAddress = 0x80,
756             // 1-byte gap, intentionall
757             Endpoint0TransmitHubAddress = 0x82,
758             Endpoint0TransmitHubPort = 0x83,
759             Endpoint0ReceiveFunctionAddress = 0x84,
760 
761             // 5-byte gap, intentionall
762 
763             Endpoint1TransmitFunctionAddress = 0x88,
764             // 1-byte gap, intentionall
765             Endpoint1TransmitHubAddress = 0x8A,
766             Endpoint1TransmitHubPort = 0x8B,
767             Endpoint1ReceiveHubAddress = 0x8E,
768             Endpoint1ReceiveHubPort = 0x8F,
769 
770             Endpoint2TransmitFunctionAddress = 0x90,
771             // 1-byte gap, intentionall
772             Endpoint2TransmitHubAddress = 0x92,
773             Endpoint2TransmitHubPort = 0x93,
774             Endpoint2ReceiveFunctionAddress = 0x94,
775             Endpoint2ReceiveHubAddress = 0x96,
776             Endpoint2ReceiveHubPort = 0x97,
777 
778             Endpoint3TransmitFunctionAddress = 0x98,
779             // 1-byte gap, intentionall
780             Endpoint3TransmitHubAddress = 0x9A,
781             Endpoint3TransmitHubPort = 0x9B,
782             Endpoint3ReceiveFunctionAddress = 0x9C,
783             Endpoint3ReceiveHubAddress = 0x9E,
784             Endpoint3ReceiveHubPort = 0x9F,
785 
786             Endpoint4TransmitFunctionAddress = 0xA0,
787             // 1-byte gap, intentionall
788             Endpoint4TransmitHubAddress = 0xA2,
789             Endpoint4TransmitHubPort = 0xA3,
790             Endpoint4ReceiveFunctionAddress = 0xA4,
791             Endpoint4ReceiveHubAddress = 0xA6,
792             Endpoint4ReceiveHubPort = 0xA7,
793 
794             Endpoint0TransmitMaximumPacketSize = 0x100,
795             Endpoint0TransmitControlStatus = 0x102,
796             Endpoint0ReceiveMaximumPacketSize = 0x104,
797             Endpoint0ReceiveControlStatus = 0x106,
798             Endpoint0ReceivePacketSize = 0x108,
799             Endpoint0TransmitType = 0x10A,
800             Endpoint0TransmitPollingInterval = 0x10B,
801             Endpoint0ReceiveType = 0x10C,
802             Endpoint0ReceivePollingInterval = 0x10D,
803             // there is an inconsistency between driver and documentation; the latter says FifoSize register should be placed at 0x10F
804             Endpoint0FifoSize = 0x10E,
805 
806             Endpoint1TransmitMaximumPacketSize = 0x110,
807             Endpoint1TransmitControlStatus = 0x112,
808             Endpoint1ReceiveMaximumPacketSize = 0x114,
809             Endpoint1ReceiveControlStatus = 0x116,
810             Endpoint1ReceivePacketSize = 0x118,
811             Endpoint1TransmitType = 0x11A,
812             Endpoint1TransmitPollingInterval = 0x11B,
813             Endpoint1ReceiveType = 0x11C,
814             Endpoint1ReceivePollingInterval = 0x11D,
815             // there is an inconsistency between driver and documentation; the latter says FifoSize register should be placed at 0x11F
816             Endpoint1FifoSize = 0x11E,
817 
818             Endpoint2TransmitMaximumPacketSize = 0x120,
819             Endpoint2TransmitControlStatus = 0x122,
820             Endpoint2ReceiveMaximumPacketSize = 0x124,
821             Endpoint2ReceiveControlStatus = 0x126,
822             Endpoint2ReceivePacketSize = 0x128,
823             Endpoint2TransmitType = 0x12A,
824             Endpoint2TransmitPollingInterval = 0x12B,
825             Endpoint2ReceiveType = 0x12C,
826             Endpoint2ReceivePollingInterval = 0x12D,
827             // there is an inconsistency between driver and documentation; the latter says FifoSize register should be placed at 0x12F
828             Endpoint2FifoSize = 0x12E,
829 
830             Endpoint3TransmitMaximumPacketSize = 0x130,
831             Endpoint3TransmitControlStatus = 0x132,
832             Endpoint3ReceiveMaximumPacketSize = 0x134,
833             Endpoint3ReceiveControlStatus = 0x136,
834             Endpoint3ReceivePacketSize = 0x138,
835             Endpoint3TransmitType = 0x13A,
836             Endpoint3TransmitPollingInterval = 0x13B,
837             Endpoint3ReceiveType = 0x13C,
838             Endpoint3ReceivePollingInterval = 0x13D,
839             // there is an inconsistency between driver and documentation; the latter says FifoSize register should be placed at 0x13F
840             Endpoint3FifoSize = 0x13E,
841 
842             Endpoint4TransmitMaximumPacketSize = 0x140,
843             Endpoint4TransmitControlStatus = 0x142,
844             Endpoint4ReceiveMaximumPacketSize = 0x144,
845             Endpoint4ReceiveControlStatus = 0x146,
846             Endpoint4ReceivePacketSize = 0x148,
847             Endpoint4TransmitType = 0x14A,
848             Endpoint4TransmitPollingInterval = 0x14B,
849             Endpoint4ReceiveType = 0x14C,
850             Endpoint4ReceivePollingInterval = 0x14D,
851             // there is an inconsistency between driver and documentation; the latter says FifoSize register should be placed at 0x14F
852             Endpoint4FifoSize = 0x14E,
853 
854             // DMA registers
855             DmaInterrupt = 0x200,
856             DmaChannel1Control = 0x204,
857             DmaChannel1Address = 0x208,
858             DmaChannel1Count = 0x20C,
859             DmaChannel2Control = 0x214,
860             DmaChannel2Address = 0x218,
861             DmaChannel2Count = 0x21C,
862             DmaChannel3Control = 0x224,
863             DmaChannel3Address = 0x228,
864             DmaChannel3Count = 0x22C,
865             DmaChannel4Control = 0x234,
866             DmaChannel4Address = 0x238,
867             DmaChannel4Count = 0x23C,
868 
869         }
870 
871         private enum HostRegisters
872         {
873             Endpoint0ControlStatusLow = 0x12,
874             EndpointNTransmitControlStatusLow = 0x12,
875 
876             Endpoint0ControlStatusHigh = 0x13,
877             EndpointNTransmitControlStatusHigh = 0x13,
878 
879             ReceiveControlStatusLow = 0x16,
880             ReceiveControlStatusHigh = 0x17
881         }
882 
883         private enum DeviceRegisters
884         {
885             Endpoint0ControlStatusLow = 0x12,
886             EndpointNTransmitControlStatusLow = 0x12,
887 
888             Endpoint0ControlStatusHigh = 0x13,
889             EndpointNTransmitControlStatusHigh = 0x13,
890 
891             ReceiveControlStatusLow = 0x16,
892             ReceiveControlStatusHigh = 0x17
893         }
894 
895         private enum VBusLevel
896         {
897             BelowSessionEnd = 0,
898             AboveSessionEndBelowAvalid = 1,
899             AboveAvalidBelowVBusValid = 2,
900             AboveVBusValid = 3
901         }
902     }
903 }
904