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