1 // 2 // Copyright (c) 2010-2019 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Threading; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Core.USB; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Utilities; 17 using Antmicro.Renode.Utilities.Packets; 18 19 namespace Antmicro.Renode.Peripherals.USB 20 { 21 public class ValentyUSB : BasicDoubleWordPeripheral, IUSBDevice, IKnownSize 22 { ValentyUSB(IMachine machine, int maximumPacketSize = 64)23 public ValentyUSB(IMachine machine, int maximumPacketSize = 64) : base(machine) 24 { 25 maxPacketSize = maximumPacketSize; 26 USBCore = new USBDeviceCore(this, customSetupPacketHandler: SetupPacketHandler); 27 DefineRegisters(); 28 } 29 Reset()30 public override void Reset() 31 { 32 base.Reset(); 33 slaveToMasterBufferVirtualBase = 0; 34 state = State.Idle; 35 36 masterToSlaveBuffer.Clear(); 37 masterToSlaveAdditionalDataBuffer.Clear(); 38 slaveToMasterBuffer.Clear(); 39 } 40 41 public long Size => 0x100; 42 43 public USBDeviceCore USBCore { get; } 44 45 public GPIO IRQ { get; } = new GPIO(); 46 DefineRegisters()47 private void DefineRegisters() 48 { 49 Registers.Endpoint0OutEventPending.Define(this) 50 .WithFlag(0, out endpoint0OutErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "error") 51 .WithFlag(1, out endpoint0OutPacketPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "packet") 52 .WithReservedBits(2, 30) 53 .WithWriteCallback((_, __) => UpdateInterrupts()) 54 ; 55 56 Registers.Endpoint0OutEventEnable.Define(this) 57 .WithFlag(0, out endpoint0OutErrorEventEnabled, name: "error") 58 .WithFlag(1, out endpoint0OutPacketEventEnabled, name: "packet") 59 .WithReservedBits(2, 30) 60 .WithWriteCallback((_, __) => UpdateInterrupts()) 61 ; 62 63 Registers.Endpoint0InEventPending.Define(this) 64 .WithFlag(0, out endpoint0InErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "error") 65 .WithFlag(1, out endpoint0InPacketPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "packet") 66 .WithReservedBits(2, 30) 67 .WithWriteCallback((_, __) => UpdateInterrupts()) 68 ; 69 70 Registers.Endpoint0InEventEnable.Define(this) 71 .WithFlag(0, out endpoint0InErrorEventEnabled, name: "error") 72 .WithFlag(1, out endpoint0InPacketEventEnabled, name: "packet") 73 .WithReservedBits(2, 30) 74 .WithWriteCallback((_, __) => UpdateInterrupts()) 75 ; 76 77 Registers.Endpoint0LastTokenRead.Define(this) 78 .WithEnumField<DoubleWordRegister, USBTokenType>(0, 2, FieldMode.Read, valueProviderCallback: _ => 79 { 80 switch(state) 81 { 82 case State.SetupTokenReceived: 83 case State.SetupTokenAcked: 84 return USBTokenType.Setup; 85 86 case State.ReadyForDataFromMaster: 87 case State.DataFromMasterAcked: 88 return USBTokenType.Out; 89 90 case State.DataToMasterReady: 91 return USBTokenType.In; 92 93 default: 94 return USBTokenType.Out; 95 } 96 }) 97 .WithReservedBits(2, 30); 98 ; 99 100 Registers.Endpoint0OutBufferEmpty.Define(this) 101 .WithFlag(0, FieldMode.Read, name: "bufferEmpty", valueProviderCallback: _ => !masterToSlaveBuffer.Any()) 102 .WithReservedBits(1, 31) 103 ; 104 105 Registers.Endpoint0OutBufferHead.Define(this) 106 .WithValueField(0, 8, name: "bufferHeadByte", 107 // this buffer works in a special way - 108 // in order to move to the next item 109 // software must execute 'write' operation 110 valueProviderCallback: _ => 111 { 112 if(masterToSlaveBuffer.Count == 0) 113 { 114 this.Log(LogLevel.Warning, "Trying to read from an empty queue"); 115 return 0u; 116 } 117 118 var result = masterToSlaveBuffer.Peek(); 119 this.Log(LogLevel.Noisy, "Reading byte from out buffer: 0x{0:X}. Bytes left: {1}", result, masterToSlaveBuffer.Count); 120 return result; 121 }, 122 writeCallback: (_, __) => masterToSlaveBuffer.Dequeue()) 123 .WithReservedBits(8, 24) 124 ; 125 126 Registers.Endpoint0OutRespond.Define(this) 127 .WithEnumField<DoubleWordRegister, USBResponse>(0, 2, writeCallback: (_, v) => 128 { 129 this.Log(LogLevel.Noisy, "Endpoint 0 OUT response set to: {0} in state {1}", v, state); 130 switch(v) 131 { 132 case USBResponse.Stall: 133 state = State.Stall; 134 HandleStall(); 135 break; 136 137 case USBResponse.Ack: 138 HandleOutAckRespond(); 139 break; 140 141 case USBResponse.NotAck: 142 // intentionally do nothing 143 break; 144 145 default: 146 this.Log(LogLevel.Warning, "Unexpected endpoint 0 OUT response: {0}. Expect problems", v); 147 state = State.Error; 148 break; 149 } 150 }) 151 .WithReservedBits(2, 30) 152 ; 153 154 Registers.Endpoint0InRespond.Define(this) 155 .WithEnumField<DoubleWordRegister, USBResponse>(0, 2, writeCallback: (_, v) => 156 { 157 this.Log(LogLevel.Noisy, "Endpoint 0 IN response set to: {0} in state {1}", v, state); 158 switch(v) 159 { 160 case USBResponse.Ack: 161 state = State.DataToMasterReady; 162 ProduceDataToMaster(); 163 break; 164 165 case USBResponse.Stall: 166 state = State.Stall; 167 HandleStall(); 168 break; 169 170 case USBResponse.NotAck: 171 // intentionally do nothing 172 break; 173 174 default: 175 this.Log(LogLevel.Warning, "Unexpected endpoint 0 IN response: {0}. Expect problems", v); 176 state = State.Error; 177 break; 178 } 179 }) 180 .WithReservedBits(2, 30) 181 ; 182 183 Registers.Endpoint0InBufferEmpty.Define(this) 184 .WithFlag(0, FieldMode.Read, name: "bufferEmpty", valueProviderCallback: _ => slaveToMasterBuffer.Count == slaveToMasterBufferVirtualBase) 185 .WithReservedBits(1, 31) 186 ; 187 188 Registers.Endpoint0InBufferHead.Define(this) 189 .WithValueField(0, 8, FieldMode.Write, name: "bufferHeadByte", 190 writeCallback: (_, b) => slaveToMasterBuffer.Enqueue((byte)b)) 191 .WithReservedBits(8, 24) 192 ; 193 194 Registers.Endpoint0InDataToggleBit.Define(this) 195 // since we don't generate separate Data0/Data1 packets in a transaction anyway, writes can be ignored 196 // we must return 0, because otherwise foboot does not work... 197 .WithFlag(0, name: "Data Toggle Bit", valueProviderCallback: _ => false) 198 .WithReservedBits(1, 31) 199 ; 200 201 Registers.Address.Define(this) 202 .WithValueField(0, 8, name: "USBAddress", 203 writeCallback: (_, val) => { USBCore.Address = (byte)val; }, 204 valueProviderCallback: _ => USBCore.Address) 205 .WithReservedBits(8, 24) 206 ; 207 } 208 SendSetupPacketResponse()209 private void SendSetupPacketResponse() 210 { 211 if(masterToSlaveAdditionalDataBuffer.Count != 0) 212 { 213 this.Log(LogLevel.Error, "Setup packet handling finished, but there is still some unhandled additional data left. Dropping it, but expect problems"); 214 masterToSlaveAdditionalDataBuffer.Clear(); 215 } 216 217 this.Log(LogLevel.Noisy, "Setup packet handled"); 218 #if DEBUG_PACKETS 219 this.Log(LogLevel.Noisy, "Response bytes: [{0}]", Misc.PrettyPrintCollectionHex(slaveToMasterBuffer)); 220 #endif 221 slaveToMasterBufferVirtualBase = 0; 222 223 if(setupPacketResultCallback == null) 224 { 225 this.Log(LogLevel.Error, "No setup packet is handled at the moment, but the software wants to send data back. It might indicate a faulty driver"); 226 return; 227 } 228 229 setupPacketResultCallback(slaveToMasterBuffer.DequeueAll()); 230 setupPacketResultCallback = null; 231 } 232 HandleStall()233 private void HandleStall() 234 { 235 this.Log(LogLevel.Debug, "Endpoint 0 stalled"); 236 237 // this could happen since HandleStall is called for both IN and OUT packets 238 if(setupPacketResultCallback == null) 239 { 240 return; 241 } 242 243 SendSetupPacketResponse(); 244 } 245 ProduceDataToMaster()246 private void ProduceDataToMaster() 247 { 248 var chunkSize = slaveToMasterBuffer.Count - slaveToMasterBufferVirtualBase; 249 slaveToMasterBufferVirtualBase = slaveToMasterBuffer.Count; 250 251 if(chunkSize < maxPacketSize) 252 { 253 this.Log(LogLevel.Noisy, "Data chunk was shorter than max packet size (0x{0:X} vs 0x{1:X}), so this is the end of data", chunkSize, maxPacketSize); 254 SendSetupPacketResponse(); 255 } 256 257 // IN packet pending means that the master is waiting for more data 258 // and slave should generate it 259 endpoint0InPacketPending.Value = true; 260 UpdateInterrupts(); 261 } 262 PrepareDataFromMaster()263 private void PrepareDataFromMaster() 264 { 265 if(masterToSlaveAdditionalDataBuffer.Count == 0) 266 { 267 this.Log(LogLevel.Warning, "Asked for additional data from master, but there is no more of it"); 268 return; 269 } 270 271 var chunk = masterToSlaveAdditionalDataBuffer.DequeueRange(maxPacketSize); 272 this.Log(LogLevel.Noisy, "Enqueuing chunk of additional data from master of size {0}", chunk.Length); 273 EnqueueDataFromMaster(chunk); 274 } 275 276 EnqueueDataFromMaster(IEnumerable<byte> data)277 private void EnqueueDataFromMaster(IEnumerable<byte> data) 278 { 279 masterToSlaveBuffer.EnqueueRange(data); 280 281 // fake 16-bit CRC 282 masterToSlaveBuffer.Enqueue(0); 283 masterToSlaveBuffer.Enqueue(0); 284 285 endpoint0OutPacketPending.Value = true; 286 UpdateInterrupts(); 287 } 288 HandleOutAckRespond()289 private void HandleOutAckRespond() 290 { 291 switch(state) 292 { 293 case State.Idle: 294 // do nothing 295 break; 296 297 case State.SetupTokenReceived: 298 state = State.SetupTokenAcked; 299 break; 300 301 case State.SetupTokenAcked: 302 case State.DataFromMasterAcked: 303 state = State.ReadyForDataFromMaster; 304 PrepareDataFromMaster(); 305 break; 306 307 case State.ReadyForDataFromMaster: 308 state = State.DataFromMasterAcked; 309 break; 310 311 default: 312 this.Log(LogLevel.Warning, "Unexpected state when handling OUT ACK response: {0}. Expect problems", state); 313 state = State.Error; 314 break; 315 } 316 } 317 UpdateInterrupts()318 private void UpdateInterrupts() 319 { 320 var irqState = (endpoint0OutPacketPending.Value && endpoint0OutPacketEventEnabled.Value) 321 || (endpoint0OutErrorPending.Value && endpoint0OutErrorEventEnabled.Value) 322 || (endpoint0InPacketPending.Value && endpoint0InPacketEventEnabled.Value) 323 || (endpoint0InErrorPending.Value && endpoint0InErrorEventEnabled.Value); 324 325 IRQ.Set(irqState); 326 } 327 328 // NOTE: Here we assume that the communication is well-formed, i.e., 329 // the controller does not send two setup packets in a row (without waiting for a response), 330 // or a device does not start to respond by itself (without the request from the master). 331 // There are some checks verifying it and printing errors, but there is no mechanism enforcing it. SetupPacketHandler(SetupPacket packet, byte[] additionalData, Action<byte[]> resultCallback)332 private void SetupPacketHandler(SetupPacket packet, byte[] additionalData, Action<byte[]> resultCallback) 333 { 334 this.Log(LogLevel.Noisy, "Received setup packet: {0}", packet.ToString()); 335 336 if(setupPacketResultCallback != null) 337 { 338 this.Log(LogLevel.Error, "Setup packet result handler is set. It means that the previous setup packet handler has not yet finished. Expect problems!"); 339 } 340 setupPacketResultCallback = resultCallback; 341 342 slaveToMasterBuffer.Clear(); 343 slaveToMasterBufferVirtualBase = 0; 344 state = State.SetupTokenReceived; 345 346 var packetBytes = Packet.Encode(packet); 347 #if DEBUG_PACKETS 348 this.Log(LogLevel.Noisy, "Setup packet bytes: [{0}]", Misc.PrettyPrintCollectionHex(packetBytes)); 349 #endif 350 EnqueueDataFromMaster(packetBytes); 351 352 // this is a trick: 353 // in fact we don't know if the master expects any data from the slave, 354 // but we can safely assume so - if there is no data, we should simply 355 // receive NAK; 356 // without generating this interrupt the slave would never know that 357 // it should generate any response and we would be stuck 358 endpoint0InPacketPending.Value = true; 359 UpdateInterrupts(); 360 361 if(additionalData != null) 362 { 363 masterToSlaveAdditionalDataBuffer.EnqueueRange(additionalData); 364 } 365 } 366 367 private Action<byte[]> setupPacketResultCallback; 368 369 private State state; 370 // in order to avoid copying data from `slaveToMasterBuffer` 371 // into another buffer it's not cleared after generating ACK 372 // packet; in order to detect how much data has been added to 373 // the buffer this variable contains the length of the buffer 374 // before the previous ACK packet 375 private int slaveToMasterBufferVirtualBase; 376 377 private IFlagRegisterField endpoint0OutPacketPending; 378 private IFlagRegisterField endpoint0InPacketPending; 379 private IFlagRegisterField endpoint0InPacketEventEnabled; 380 private IFlagRegisterField endpoint0InErrorEventEnabled; 381 private IFlagRegisterField endpoint0InErrorPending; 382 private IFlagRegisterField endpoint0OutPacketEventEnabled; 383 private IFlagRegisterField endpoint0OutErrorEventEnabled; 384 private IFlagRegisterField endpoint0OutErrorPending; 385 386 private readonly int maxPacketSize; 387 private readonly Queue<byte> masterToSlaveBuffer = new Queue<byte>(); 388 private readonly Queue<byte> masterToSlaveAdditionalDataBuffer = new Queue<byte>(); 389 private readonly Queue<byte> slaveToMasterBuffer = new Queue<byte>(); 390 391 private enum USBResponse 392 { 393 Ack, 394 NotAck, 395 None, 396 Stall 397 } 398 399 private enum USBTokenType 400 { 401 Out = 0, 402 StartOfFrame = 1, 403 In = 2, 404 Setup = 3 405 } 406 407 private enum State 408 { 409 Idle, 410 Stall, 411 DataToMasterReady, 412 ReadyForDataFromMaster, 413 SetupTokenReceived, 414 SetupTokenAcked, 415 DataFromMasterAcked, 416 Error, 417 } 418 419 private enum Registers 420 { 421 PullupOut = 0x0, 422 423 Endpoint0OutEventStatus = 0x4, 424 Endpoint0OutEventPending = 0x08, 425 Endpoint0OutEventEnable = 0x0C, 426 Endpoint0LastTokenRead = 0x10, 427 Endpoint0OutRespond = 0x14, 428 Endpoint0OutDataToggleBit = 0x18, 429 Endpoint0OutBufferHead = 0x1C, 430 Endpoint0OutBufferEmpty = 0x20, 431 432 Endpoint0InEventStatus = 0x24, 433 Endpoint0InEventPending = 0x28, 434 Endpoint0InEventEnable = 0x2C, 435 Endpoint0InLastToken = 0x30, 436 Endpoint0InRespond = 0x34, 437 Endpoint0InDataToggleBit = 0x38, 438 Endpoint0InBufferHead = 0x3C, 439 Endpoint0InBufferEmpty = 0x40, 440 441 Endpoint1InEventStatus = 0x44, 442 Endpoint1InEventPending = 0x48, 443 Endpoint1InEventEnable = 0x4C, 444 Endpoint1InLastToken = 0x50, 445 Endpoint1InRespond = 0x54, 446 Endpoint1InDataToggleBit = 0x58, 447 Endpoint1InBufferHead = 0x5C, 448 Endpoint1InBufferEmpty = 0x60, 449 450 Endpoint2OutEventStatus = 0x64, 451 Endpoint2OutEventPending = 0x68, 452 Endpoint2OutEventEnable = 0x6C, 453 Endpoint2OutLastToken = 0x70, 454 Endpoint2OutRespond = 0x74, 455 Endpoint2OutDataToggleBit = 0x78, 456 Endpoint2OutBufferHead = 0x7C, 457 Endpoint2OutBufferEmpty = 0x80, 458 459 Endpoint2InEventStatus = 0x84, 460 Endpoint2InEventPending = 0x88, 461 Endpoint2InEventEnable = 0x8C, 462 Endpoint2InLastToken = 0x90, 463 Endpoint2InRespond = 0x94, 464 Endpoint2InDataToggleBit = 0x98, 465 Endpoint2InBufferHead = 0x9C, 466 Endpoint2InBufferEmpty = 0xA0, 467 468 Address = 0xA4 469 } 470 } 471 } 472