1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using System.Collections.Generic; 14 using System.Linq; 15 16 namespace Antmicro.Renode.Peripherals.USBDeprecated 17 { 18 public class EHCIHostController : IDoubleWordPeripheral, IPeripheralRegister<IUSBHub, USBRegistrationPoint>, IPeripheralContainer<IUSBPeripheral, USBRegistrationPoint>, IDisposable 19 { EHCIHostController(IMachine machine, uint ehciBaseAddress = 0x100, uint capabilityRegistersLength = 0x40, uint numberOfPorts = 1, uint? ulpiBaseAddress = 0x170)20 public EHCIHostController(IMachine machine, uint ehciBaseAddress = 0x100, uint capabilityRegistersLength = 0x40, uint numberOfPorts = 1, uint? ulpiBaseAddress = 0x170) 21 { 22 this.machine = machine; 23 sysbus = machine.GetSystemBus(this); 24 this.numberOfPorts = numberOfPorts; 25 26 this.ehciBaseAddress = ehciBaseAddress; 27 if(ulpiBaseAddress.HasValue) 28 { 29 ulpiChip = new Ulpi(ulpiBaseAddress.Value); 30 } 31 capabilitiesLength = capabilityRegistersLength; 32 33 IRQ = new GPIO(); 34 registeredDevices = new Dictionary<byte, IUSBPeripheral>(); 35 addressedDevices = new Dictionary<byte, IUSBPeripheral>(); 36 registeredHubs = new ReusableIdentifiedList<IUSBHub>(); 37 interruptEnableRegister = new InterruptEnable(); 38 thisLock = new Object(); 39 40 portStatusControl = new PortStatusAndControlRegister[numberOfPorts]; //port status control 41 for(int i = 0; i< portStatusControl.Length; i++) 42 { 43 portStatusControl[i] = new PortStatusAndControlRegister(); 44 } 45 46 asyncThread = machine.ObtainManagedThread(AsyncListScheduleThread, 100); 47 periodicThread = machine.ObtainManagedThread(PeriodicListScheduleThread, 100); 48 49 SoftReset(); //soft reset must be done before attaching devices 50 51 periodic_qh = new QueueHead(sysbus); 52 async_qh = new QueueHead(sysbus); 53 } 54 Dispose()55 public void Dispose() 56 { 57 asyncThread.Dispose(); 58 periodicThread.Dispose(); 59 } 60 Register(IUSBPeripheral peripheral, USBRegistrationPoint registrationPoint)61 public void Register(IUSBPeripheral peripheral, USBRegistrationPoint registrationPoint) 62 { 63 machine.RegisterAsAChildOf(this, peripheral, registrationPoint); 64 AttachDevice(peripheral, registrationPoint.Address.Value); 65 } 66 Register(IUSBHub peripheral, USBRegistrationPoint registrationPoint)67 public void Register(IUSBHub peripheral, USBRegistrationPoint registrationPoint) 68 { 69 machine.RegisterAsAChildOf(this, peripheral, registrationPoint); 70 AttachDevice(peripheral, registrationPoint.Address.Value); 71 RegisterHub(peripheral); 72 return; 73 } 74 Unregister(IUSBHub peripheral)75 public void Unregister(IUSBHub peripheral) 76 { 77 byte port = registeredDevices.FirstOrDefault(x => x.Value == peripheral).Key; 78 DetachDevice(port); 79 machine.UnregisterAsAChildOf(this, peripheral); 80 registeredDevices.Remove(port); 81 registeredHubs.Remove(peripheral); 82 } 83 Unregister(IUSBPeripheral peripheral)84 public void Unregister(IUSBPeripheral peripheral) 85 { 86 byte port = registeredDevices.FirstOrDefault(x => x.Value == peripheral).Key; 87 DetachDevice(port); 88 machine.UnregisterAsAChildOf(this, peripheral); 89 registeredDevices.Remove(port); 90 // TODO: why do we remove from hubs here? 91 registeredHubs.RemoveAt(port); 92 } 93 AttachDevice(IUSBPeripheral device, byte port)94 public void AttachDevice(IUSBPeripheral device, byte port) 95 { 96 registeredDevices.Add(port, device); 97 PortStatusAndControlRegisterChanges change = portStatusControl[port - 1].Attach(device); 98 99 if(change.ConnectChange) 100 { 101 usbStatus |= (uint)InterruptMask.PortChange; 102 } 103 104 if(interruptEnableRegister.Enable && interruptEnableRegister.PortChangeEnable) 105 { 106 usbStatus |= (uint)InterruptMask.USBInterrupt | (uint)InterruptMask.PortChange; 107 IRQ.Set(true); 108 } 109 defaultDevice = device; 110 activeDevice = device; 111 } 112 DetachDevice(byte port)113 public void DetachDevice(byte port) 114 { 115 registeredDevices.Remove(port); 116 var change = portStatusControl[port - 1].Detach(); 117 118 if(change.ConnectChange) 119 { 120 usbStatus |= (uint)InterruptMask.PortChange; 121 } 122 123 if(interruptEnableRegister.Enable && interruptEnableRegister.PortChangeEnable) 124 { 125 usbStatus |= (uint)InterruptMask.USBInterrupt | (uint)InterruptMask.PortChange; 126 IRQ.Set(true); 127 } 128 } 129 GetRegistrationPoints(IUSBPeripheral peripheral)130 public IEnumerable<USBRegistrationPoint> GetRegistrationPoints(IUSBPeripheral peripheral) 131 { 132 throw new NotImplementedException(); 133 } 134 135 public GPIO IRQ { get; private set; } 136 137 public IEnumerable<IRegistered<IUSBPeripheral, USBRegistrationPoint>> Children 138 { 139 get 140 { 141 throw new NotImplementedException(); 142 } 143 } 144 ReadDoubleWord(long address)145 public virtual uint ReadDoubleWord(long address) 146 { 147 long shift; 148 if(address.InRange(ehciBaseAddress, capabilitiesLength, out shift)) 149 { 150 switch((CapabilityRegisters)shift) 151 { 152 case CapabilityRegisters.CapabilityRegistersLength: 153 return (hciVersion & EhciHciVersionMask) << EhciHciVersionOffset | (capabilitiesLength & EhciCapabilityRegistersLengthMask); 154 case CapabilityRegisters.StructuralParameters: 155 return ((uint)(portStatusControl.Length) & hcsparamsNPortsMask); 156 } 157 } 158 else if(address.InRange(ehciBaseAddress + capabilitiesLength, EhciPortStatusControlRegisterOffset + numberOfPorts * EhciPortStatusControlRegisterWidth, out shift)) 159 { 160 switch((OperationalRegisters)shift) 161 { 162 case OperationalRegisters.UsbCommand: 163 return usbCommand & (~0x04u); 164 case OperationalRegisters.UsbStatus: 165 //TODO: check locking 166 lock(thisLock) 167 { 168 return usbStatus; 169 } 170 case OperationalRegisters.UsbInterruptEnable: 171 return interruptEnableRegister.Value; 172 case OperationalRegisters.UsbFrameIndex: 173 usbFrameIndex = usbFrameIndex + 4; 174 usbFrameIndex &= 0x1f; 175 return usbFrameIndex & ~0x7u; 176 case OperationalRegisters.PeriodicListBaseAddress: 177 return periodicAddress; 178 case OperationalRegisters.AsyncListAddress: 179 return asyncAddress; 180 case OperationalRegisters.ConfiguredFlag: 181 return configFlag; 182 default: 183 if(shift >= EhciPortStatusControlRegisterOffset) 184 { 185 var portNumber = (shift - EhciPortStatusControlRegisterOffset) / EhciPortStatusControlRegisterWidth; 186 return portStatusControl[portNumber].getValue(); 187 } 188 break; 189 } 190 } 191 192 switch((OtherRegisters)address) 193 { 194 case OtherRegisters.UsbMode: 195 return (uint)mode; 196 case OtherRegisters.UsbDCCParams: 197 return EhciNumberOfEndpoints; 198 default: 199 if(ulpiChip != null && address == ulpiChip.BaseAddress) 200 { 201 return (uint)(ulpiChip.LastReadValue << UlpiDataReadOffset) | UlpiSyncStateMask; 202 } 203 break; 204 } 205 206 this.LogUnhandledRead(address); 207 return 0; 208 } 209 WriteDoubleWord(long address, uint value)210 public virtual void WriteDoubleWord(long address, uint value) 211 { 212 long shift; 213 if(address.InRange(ehciBaseAddress + capabilitiesLength, EhciPortStatusControlRegisterOffset + numberOfPorts * EhciPortStatusControlRegisterWidth, out shift)) 214 { 215 switch((OperationalRegisters)shift) 216 { 217 case OperationalRegisters.UsbCommand: 218 lock(thisLock) 219 { 220 usbCommand = value; 221 if((value & (uint)EhciUsbCommandMask.HostControllerReset) != 0) 222 { 223 usbCommand &= ~(uint)EhciUsbCommandMask.HostControllerReset; // clear reset bit 224 SoftReset(); 225 return; 226 } 227 } 228 if((value & (uint)EhciUsbCommandMask.AsynchronousScheduleEnable) == 0) //if disable async schedule 229 { 230 if ((usbStatus & (uint)EhciUsbStatusMask.AsynchronousScheduleStatus) != 0) 231 { 232 lock(thisLock) 233 { 234 usbStatus &= ~(uint)EhciUsbStatusMask.AsynchronousScheduleStatus; 235 } 236 asyncThread.Stop(); 237 } 238 } 239 else 240 { 241 lock(thisLock) 242 { 243 usbStatus |= (uint)EhciUsbStatusMask.Reclamation; //raise reclamation 244 } 245 if((usbStatus & (uint)EhciUsbStatusMask.AsynchronousScheduleStatus) == 0) 246 { 247 lock(thisLock) 248 { 249 usbStatus |= (uint)EhciUsbStatusMask.AsynchronousScheduleStatus; //confirm async schedule enable 250 } 251 asyncThread.Start(); 252 } 253 } 254 if((value & (uint)EhciUsbCommandMask.PeriodicScheduleEnable) != 0) 255 { 256 lock(thisLock) 257 { 258 usbStatus |= (uint)EhciUsbStatusMask.PeriodicScheduleStatus; 259 } 260 periodicThread.Start(); 261 } 262 else 263 { 264 periodicThread.Stop(); 265 lock(thisLock) 266 { 267 usbStatus &= ~(uint)EhciUsbStatusMask.PeriodicScheduleStatus; 268 } 269 } 270 if((value & (uint)EhciUsbCommandMask.RunStop) != 0) 271 { 272 lock(thisLock) 273 { 274 usbStatus &= ~(uint)EhciUsbStatusMask.HCHalted; //clear HCHalted bit in USB status reg 275 } 276 foreach(var port in portStatusControl) 277 { 278 port.Enable(); 279 } 280 } 281 else 282 { 283 lock(thisLock) 284 { 285 usbStatus |= (uint)EhciUsbStatusMask.HCHalted; //set HCHalted bit in USB status reg 286 } 287 } 288 if((value & (uint)EhciUsbCommandMask.InterruptOnAsyncAdvanceDoorbell) != 0) 289 { 290 lock(thisLock) 291 { 292 usbCommand &= ~(uint)EhciUsbCommandMask.InterruptOnAsyncAdvanceDoorbell; 293 usbStatus |= (uint)EhciUsbStatusMask.InterruptOnAsyncAdvance; 294 } 295 } 296 return; 297 case OperationalRegisters.AsyncListAddress: 298 lock(thisLock) 299 { 300 asyncAddress = value; 301 } 302 return; 303 case OperationalRegisters.PeriodicListBaseAddress: 304 lock(thisLock) 305 { 306 periodicAddress = value; 307 } 308 return; 309 case OperationalRegisters.UsbInterruptEnable: 310 interruptEnableRegister.OnAsyncAdvanceEnable = ((value & (uint)InterruptMask.InterruptOnAsyncAdvance) != 0); 311 interruptEnableRegister.HostSystemErrorEnable = ((value & (uint)InterruptMask.HostSystemError) != 0); 312 interruptEnableRegister.FrameListRolloverEnable = ((value & (uint)InterruptMask.FrameListRollover) != 0); 313 interruptEnableRegister.PortChangeEnable = ((value & (uint)InterruptMask.PortChange) != 0); 314 interruptEnableRegister.USBErrorEnable = ((value & (uint)InterruptMask.USBError) != 0); 315 interruptEnableRegister.Enable = ((value & (uint)InterruptMask.USBInterrupt) != 0); 316 317 if(interruptEnableRegister.Enable && interruptEnableRegister.PortChangeEnable) 318 { 319 foreach(var register in portStatusControl) 320 { 321 if((register.getValue() & PortStatusAndControlRegister.ConnectStatusChange) != 0) 322 { 323 IRQ.Set(false); 324 lock(thisLock) 325 { 326 usbStatus |= (uint)InterruptMask.USBInterrupt | (uint)InterruptMask.PortChange; 327 } 328 IRQ.Set(true); 329 return; 330 } 331 } 332 } 333 return; 334 case OperationalRegisters.UsbStatus: 335 lock(thisLock) 336 { 337 usbStatus &= ~value; 338 if((usbStatus & (uint)InterruptMask.USBInterrupt) == 0) 339 { 340 IRQ.Set(false); 341 } 342 } 343 return; 344 case OperationalRegisters.ConfiguredFlag: 345 configFlag = value; 346 return; 347 default: 348 if(shift >= EhciPortStatusControlRegisterOffset) 349 { 350 var portNumber = (shift - EhciPortStatusControlRegisterOffset) / EhciPortStatusControlRegisterWidth; 351 352 PortStatusAndControlRegisterChanges change; 353 portStatusControl[portNumber].setValue(portStatusControl[portNumber].getValue() & (~(value & 0x0000002a))); 354 portStatusControl[portNumber].setValue(portStatusControl[portNumber].getValue() & ((value) | (~(1u << 2)))); 355 356 value &= 0x007011c0; 357 358 change = portStatusControl[portNumber].setValue(value & (~(1u << 2))); 359 if((portStatusControl[portNumber].getValue() & (1u << 8)) != 0 && (value & (1u << 8)) == 0) 360 { 361 portStatusControl[portNumber].setValue((portStatusControl[portNumber].getValue() & (~(1u << 1)))); 362 value |= 1 << 2; 363 change = portStatusControl[portNumber].setValue((portStatusControl[portNumber].getValue() & 0x007011c0) | value); 364 } 365 366 if(change.ConnectChange) 367 { 368 lock(thisLock) 369 { 370 usbStatus |= (uint)InterruptMask.PortChange; 371 } 372 } 373 374 if((interruptEnableRegister.Enable) && (interruptEnableRegister.PortChangeEnable)) 375 { 376 lock(thisLock) 377 { 378 usbStatus |= (uint)InterruptMask.USBInterrupt | (uint)InterruptMask.PortChange; 379 } 380 IRQ.Set(true); 381 } 382 return; 383 } 384 break; 385 } 386 } 387 388 switch((OtherRegisters)address) 389 { 390 case OtherRegisters.UsbMode: 391 mode = (ControllerMode)(value & 0x3); 392 break; 393 default: 394 if(ulpiChip != null && address == ulpiChip.BaseAddress) 395 { 396 var isReadOperation = (value & UlpiRdWrMask) == 0; 397 var ulpiRegister = (byte)((value & UlpiRegAddrMask) >> UlpiRegAddrOffset); 398 if(isReadOperation) 399 { 400 // we don't need read value here, as it will be stored in `LastReadValue` property of `ulpiChip` 401 ulpiChip.Read(ulpiRegister); 402 } 403 else 404 { 405 var valueToWrite = (byte)(value & UlpiDataWriteMask); 406 ulpiChip.Write(ulpiRegister, valueToWrite); 407 } 408 } 409 else 410 { 411 this.LogUnhandledWrite(address, value); 412 } 413 break; 414 } 415 } 416 Reset()417 public virtual void Reset() 418 { 419 SoftReset(); 420 activeDevice = defaultDevice; // TODO: why ? 421 } 422 SoftReset()423 private void SoftReset() 424 { 425 addressedDevices.Clear(); 426 foreach(var port in portStatusControl) 427 { 428 port.setValue(0x00001000); 429 port.powerUp(); 430 } 431 432 asyncThread.Stop(); 433 periodicThread.Stop(); 434 435 usbCommand = 0x80000; //usb command 436 usbStatus = 0x1000; //usb status 437 usbFrameIndex = 0; //usb frame index 438 asyncAddress = 0; 439 periodicAddress = 0; //next async addres 440 configFlag = 0; // configured flag registers 441 442 mode = ControllerMode.Idle; 443 interruptEnableRegister.Clear(); 444 periodic_qh = new QueueHead(sysbus); 445 async_qh = new QueueHead(sysbus); 446 } 447 GetFrs()448 private uint GetFrs() 449 { 450 switch((usbCommand >> 2) & 0x3) 451 { 452 case 1: 453 return 512; 454 case 2: 455 return 256; 456 default: 457 return 1024; 458 } 459 } 460 PeriodicListScheduleThread()461 private void PeriodicListScheduleThread() 462 { 463 for(uint counter = 0; counter < GetFrs(); counter += 4) 464 { 465 ProcessList(false, counter); 466 } 467 } 468 AsyncListScheduleThread()469 private void AsyncListScheduleThread() 470 { 471 ProcessList(); 472 } 473 RegisterHub(IUSBHub hub)474 private void RegisterHub(IUSBHub hub) 475 { 476 registeredHubs.Add(hub); 477 hub.RegisterHub += h => 478 { 479 registeredHubs.Add(h); 480 }; 481 hub.ActiveDevice += d => 482 { 483 activeDevice = d; 484 }; 485 } 486 GetTargetDevice(QueueHead qh)487 private IUSBPeripheral GetTargetDevice(QueueHead qh) 488 { 489 if((qh.Overlay.Status & StatusActive) == 0) 490 { 491 return null; 492 } 493 IUSBPeripheral targetDevice; 494 495 if(qh.DeviceAddress != 0) 496 { 497 targetDevice = FindDevice(qh.DeviceAddress); 498 } 499 else 500 { 501 if(qh.HubAddress == 0 && qh.PortNumber == 0) 502 { 503 targetDevice = activeDevice; 504 } 505 else if(qh.HubAddress != 0) 506 { 507 targetDevice = FindDevice(qh.HubAddress, qh.PortNumber); 508 } 509 else 510 { 511 targetDevice = activeDevice; 512 } 513 } 514 return targetDevice; 515 } 516 ProcessList(bool async = true, uint counter = 0)517 private void ProcessList(bool async = true, uint counter = 0) 518 { 519 QueueHead qh; 520 lock(thisLock) 521 { 522 if(async) 523 { 524 qh = async_qh; 525 qh.Address = asyncAddress; 526 } 527 else 528 { 529 qh = periodic_qh; 530 qh.Address = (periodicAddress & 0xfffff000u) + (counter & 0xFFCu); 531 } 532 if(!qh.IsValid || (qh.ElementName != 0x01)) 533 { 534 return; 535 } 536 537 if(qh.GoToNextLink()) 538 { 539 qh.Fetch(); 540 qh.Advance(); 541 if((qh.TransferDescriptor.Status & StatusActive) == 0) 542 { 543 return; 544 } 545 } 546 547 IUSBPeripheral targetDevice = GetTargetDevice(qh); 548 if(targetDevice == null) 549 { 550 return; 551 } 552 USBPacket packet; 553 packet.bytesToTransfer = qh.Overlay.TotalBytesToTransfer; 554 packet.ep = qh.EndpointNumber; 555 packet.data = null; 556 uint dataAmount; 557 switch(qh.Overlay.PID) 558 { 559 case PIDCode.In://data transfer from device to host 560 this.NoisyLog("[process_{0}_list] IN {1:d} [{2}]", async ? "async" : "periodic", qh.Overlay.TotalBytesToTransfer, targetDevice); 561 if(qh.Overlay.TotalBytesToTransfer == 0) 562 { 563 break; 564 } 565 byte[] inData = null; 566 this.NoisyLog("[process_{0}_list] EP {1:d}", async ? "async" : "periodic", qh.EndpointNumber); 567 if(async) 568 { 569 if(qh.EndpointNumber == 0) 570 { 571 inData = targetDevice.GetDataControl(packet); 572 this.NoisyLog("[process_list] CONT"); 573 } 574 else 575 { 576 inData = targetDevice.GetDataBulk(packet); 577 this.NoisyLog("[process_list] BULK"); 578 } 579 } 580 else 581 { 582 inData = targetDevice.WriteInterrupt(packet); 583 } 584 uint inputSourceArray = 0; 585 uint bytesToTransfer = (inData == null) ? 0 : (uint)inData.Length; 586 while(bytesToTransfer > 0) 587 { 588 for(int i = 0; i < qh.Overlay.BufferPointer.Length; i++) 589 { 590 if((qh.Overlay.BufferPointer[i] == 0) || (bytesToTransfer == 0)) 591 { 592 break; 593 } 594 dataAmount = Math.Min(bytesToTransfer, 4096); 595 var dataToSend = new byte[dataAmount]; 596 Array.Copy(inData, inputSourceArray, dataToSend, 0, dataAmount); 597 bytesToTransfer -= dataAmount; 598 inputSourceArray += dataAmount; 599 sysbus.WriteBytes(dataToSend, qh.Overlay.BufferPointer[i] | qh.Overlay.CurrentOffset, (int)dataAmount); 600 qh.UpdateTotalBytesToTransfer(Math.Min(dataAmount, qh.Overlay.TotalBytesToTransfer)); 601 } 602 } 603 break; 604 case PIDCode.Setup://if setup command 605 this.NoisyLog("[async] SETUP {0:d}", qh.Overlay.TotalBytesToTransfer); 606 this.NoisyLog("[async] Device {0:d} [{1}]", qh.DeviceAddress, targetDevice); 607 608 setupData = new USBSetupPacket(); 609 setupData.requestType = sysbus.ReadByte(qh.Overlay.BufferPointer[0] | qh.Overlay.CurrentOffset); 610 setupData.request = sysbus.ReadByte(qh.Overlay.BufferPointer[0] | qh.Overlay.CurrentOffset + 1); 611 setupData.value = sysbus.ReadWord(qh.Overlay.BufferPointer[0] | qh.Overlay.CurrentOffset + 2); 612 setupData.index = sysbus.ReadWord(qh.Overlay.BufferPointer[0] | qh.Overlay.CurrentOffset + 4); 613 setupData.length = sysbus.ReadWord(qh.Overlay.BufferPointer[0] | qh.Overlay.CurrentOffset + 6); 614 615 if(((setupData.requestType & 0x80u) >> 7) == (uint)DataDirection.DeviceToHost)//if device to host transfer 616 { 617 if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Standard) 618 { 619 switch((DeviceRequestType)setupData.request) 620 { 621 case DeviceRequestType.GetDescriptor: 622 targetDevice.GetDescriptor(packet, setupData); 623 break; 624 case DeviceRequestType.GetConfiguration: 625 targetDevice.GetConfiguration(); 626 break; 627 case DeviceRequestType.GetInterface: 628 targetDevice.GetInterface(packet, setupData); 629 break; 630 case DeviceRequestType.GetStatus: 631 targetDevice.GetStatus(packet, setupData); 632 break; 633 default: 634 targetDevice.GetDescriptor(packet, setupData); 635 this.Log(LogLevel.Warning, "[async] Unsupported device request"); 636 break; 637 }//end of switch request 638 } 639 else if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Class) 640 { 641 targetDevice.ProcessClassGet(packet, setupData); 642 } 643 else if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Vendor) 644 { 645 targetDevice.ProcessVendorGet(packet, setupData); 646 } 647 } 648 else//if host to device transfer 649 if(((setupData.requestType & 0x60) >> 5) == (uint)USBRequestType.Standard) 650 { 651 switch((DeviceRequestType)setupData.request) 652 { 653 case DeviceRequestType.SetAddress: 654 targetDevice.SetAddress(setupData.value); 655 AddressDevice(targetDevice, (byte)setupData.value); 656 break; 657 case DeviceRequestType.SetDescriptor: 658 targetDevice.GetDescriptor(packet, setupData); 659 break; 660 case DeviceRequestType.SetFeature: 661 targetDevice.GetDescriptor(packet, setupData); 662 break; 663 case DeviceRequestType.SetInterFace: 664 targetDevice.SetInterface(packet, setupData); 665 break; 666 case DeviceRequestType.SetConfiguration: 667 targetDevice.SetConfiguration(packet, setupData); 668 break; 669 default: 670 this.Log(LogLevel.Warning, "[async] Unsupported device request [ {0:X} ]", setupData.request); 671 break; 672 }//end of switch request 673 }//end of request type.standard 674 else if((setupData.requestType >> 5) == (uint)USBRequestType.Class) 675 { 676 targetDevice.ProcessClassSet(packet, setupData); 677 } 678 else if((setupData.requestType >> 5) == (uint)USBRequestType.Vendor) 679 { 680 targetDevice.ProcessVendorSet(packet, setupData); 681 } 682 qh.UpdateTotalBytesToTransfer(qh.Overlay.TotalBytesToTransfer); 683 break; 684 685 case PIDCode.Out://data transfer from host to device 686 this.NoisyLog("[async] OUT {0:d}", qh.Overlay.TotalBytesToTransfer); 687 dataAmount = qh.Overlay.TotalBytesToTransfer; 688 689 var data = new byte[qh.Overlay.TotalBytesToTransfer]; 690 691 var bytesTransferred = 0; 692 while(qh.Overlay.TotalBytesToTransfer > 0) 693 { 694 for(var i = 0; i < qh.Overlay.BufferPointer.Length; i++) 695 { 696 if(qh.Overlay.BufferPointer[i] == 0) 697 { 698 break; 699 } 700 if(qh.Overlay.TotalBytesToTransfer == 0) 701 { 702 break; 703 } 704 var transferredThisTurn = Math.Min(4096, (int)qh.Overlay.TotalBytesToTransfer); 705 706 //get data 707 sysbus.ReadBytes(qh.Overlay.BufferPointer[i] | qh.Overlay.CurrentOffset, transferredThisTurn, data, bytesTransferred); 708 bytesTransferred += transferredThisTurn; 709 qh.UpdateTotalBytesToTransfer((uint)transferredThisTurn); 710 } 711 712 if(bytesTransferred > 0) 713 { 714 packet.data = data; 715 if(qh.EndpointNumber == 0) 716 { 717 if(((setupData.requestType & 0x80u) >> 7) == (uint)DataDirection.DeviceToHost)//if device to host transfer 718 { 719 if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Standard) 720 { 721 switch((DeviceRequestType)setupData.request) 722 { 723 case DeviceRequestType.GetDescriptor: 724 targetDevice.GetDescriptor(packet, setupData); 725 break; 726 case DeviceRequestType.GetConfiguration: 727 targetDevice.GetConfiguration(); 728 break; 729 case DeviceRequestType.GetInterface: 730 targetDevice.GetInterface(packet, setupData); 731 break; 732 case DeviceRequestType.GetStatus: 733 targetDevice.GetStatus(packet, setupData); 734 break; 735 default: 736 targetDevice.GetDescriptor(packet, setupData); 737 this.Log(LogLevel.Warning, "[process_{0}_list] Unsupported device request1", async ? "async" : "periodic"); 738 break; 739 }//end of switch request 740 } 741 else if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Class) 742 { 743 targetDevice.ProcessClassGet(packet, setupData); 744 } 745 else if(((setupData.requestType & 0x60u) >> 5) == (uint)USBRequestType.Vendor) 746 { 747 targetDevice.ProcessVendorGet(packet, setupData); 748 } 749 } 750 else//if host to device transfer 751 if(((setupData.requestType & 0x60) >> 5) == (uint)USBRequestType.Standard) 752 { 753 switch((DeviceRequestType)setupData.request) 754 { 755 case DeviceRequestType.SetAddress: 756 targetDevice.SetAddress(setupData.value); 757 AddressDevice(targetDevice, (byte)setupData.value); 758 break; 759 case DeviceRequestType.SetDescriptor: 760 targetDevice.GetDescriptor(packet, setupData); 761 break; 762 case DeviceRequestType.SetFeature: 763 targetDevice.GetDescriptor(packet, setupData); 764 break; 765 case DeviceRequestType.SetInterFace: 766 targetDevice.SetInterface(packet, setupData); 767 break; 768 case DeviceRequestType.SetConfiguration: 769 targetDevice.SetConfiguration(packet, setupData); 770 break; 771 default: 772 this.Log(LogLevel.Warning, "[process_{0}_list] Unsupported device request [ {1:X} ]", async ? "async" : "periodic", setupData.request); 773 break; 774 }//end of switch request 775 }//end of request type.standard 776 else if((setupData.requestType >> 5) == (uint)USBRequestType.Class) 777 { 778 targetDevice.ProcessClassSet(packet, setupData); 779 } 780 else if((setupData.requestType >> 5) == (uint)USBRequestType.Vendor) 781 { 782 targetDevice.ProcessVendorSet(packet, setupData); 783 } 784 break; 785 } 786 } 787 targetDevice.WriteDataBulk(packet); 788 } 789 break; 790 default: 791 this.Log(LogLevel.Warning, "[process_list] Unknown PID"); 792 return; 793 } 794 795 qh.Processed(); 796 qh.StaticMemoryUpdate(); 797 qh.Overlay.UpdateMemory(); 798 qh.WriteBackTransferDescriptor(); 799 qh.StaticMemoryUpdate(); 800 801 if(interruptEnableRegister.Enable && (async || interruptEnableRegister.FrameListRolloverEnable) && (!async || interruptEnableRegister.OnAsyncAdvanceEnable)) 802 { 803 if((async && qh.Overlay.InterruptOnComplete) || (!async && (usbFrameIndex > GetFrs()))) 804 { 805 usbStatus |= (uint)InterruptMask.USBInterrupt; 806 if(async) 807 { 808 usbStatus |= (uint)InterruptMask.PortChange; 809 } 810 else 811 { 812 usbStatus |= (uint)InterruptMask.FrameListRollover; 813 usbFrameIndex -= GetFrs(); 814 } 815 this.NoisyLog("[process_{0}_list] INT IN", async ? "async" : "periodic"); 816 IRQ.Set(true); 817 } 818 } 819 } 820 } 821 AddressDevice(IUSBPeripheral device, byte address)822 private void AddressDevice(IUSBPeripheral device, byte address) 823 { 824 if(!addressedDevices.ContainsKey(address))//XXX: Linux hack 825 { 826 addressedDevices.Add(address, device); 827 } 828 } 829 FindDevice(byte hubNumber, byte portNumber)830 private IUSBPeripheral FindDevice(byte hubNumber, byte portNumber) 831 { 832 return addressedDevices.ContainsKey(hubNumber) 833 ? ((IUSBHub)addressedDevices[hubNumber]).GetDevice(portNumber) 834 : registeredDevices[portNumber]; 835 } 836 FindDevice(byte deviceAddress)837 private IUSBPeripheral FindDevice(byte deviceAddress) 838 { 839 return !addressedDevices.ContainsKey(deviceAddress) 840 ? null 841 : addressedDevices[deviceAddress]; 842 } 843 844 private readonly Dictionary<byte,IUSBPeripheral> registeredDevices; 845 private readonly ReusableIdentifiedList<IUSBHub> registeredHubs; 846 private readonly Dictionary<byte,IUSBPeripheral> addressedDevices; 847 private readonly InterruptEnable interruptEnableRegister; 848 private readonly PortStatusAndControlRegister[] portStatusControl; 849 private readonly Object thisLock; 850 private readonly IManagedThread asyncThread; 851 private readonly IManagedThread periodicThread; 852 private readonly IMachine machine; 853 private readonly IBusController sysbus; 854 855 private uint usbCommand; 856 private uint usbStatus; 857 private uint usbFrameIndex; 858 private uint periodicAddress; 859 private uint asyncAddress; 860 private uint configFlag; 861 private uint ehciBaseAddress; 862 863 private ControllerMode mode; 864 private Ulpi ulpiChip; 865 866 private IUSBPeripheral activeDevice; 867 private IUSBPeripheral defaultDevice; 868 869 private uint capabilitiesLength; 870 private uint numberOfPorts; 871 872 private USBSetupPacket setupData; 873 private QueueHead periodic_qh; 874 private QueueHead async_qh; 875 876 private const int UlpiRdWrMask = (1 << 29); 877 private const int UlpiRegAddrOffset = 16; 878 private const int UlpiRegAddrMask = 0xFF << UlpiRegAddrOffset; 879 private const int UlpiDataWriteMask = 0xFF; 880 private const int UlpiDataReadOffset = 8; 881 private const int UlpiSyncStateMask = (1 << 27); 882 private const uint StatusActive = 1u << 7; 883 private const uint hcsparamsNPortsMask = 0xf; 884 private const uint hciVersion = 0x0100; //hci version (16 bit BCD) 885 886 private const int EhciHciVersionMask = 0xffff; 887 private const int EhciHciVersionOffset = 16; 888 private const int EhciCapabilityRegistersLengthMask = 0xff; 889 private const int EhciPortStatusControlRegisterOffset = 0x44; 890 private const int EhciPortStatusControlRegisterWidth = 0x4; 891 892 private const uint EhciNumberOfEndpoints = 0x10; 893 894 private class ReusableIdentifiedList<T> where T: class 895 { ReusableIdentifiedList()896 public ReusableIdentifiedList() 897 { 898 internalList = new List<T>(); 899 } 900 Add(T element)901 public int Add(T element) 902 { 903 var firstEmpty = internalList.IndexOf(null); 904 if(firstEmpty != -1) 905 { 906 internalList[firstEmpty] = element; 907 return firstEmpty; 908 } 909 910 internalList.Add(element); 911 return internalList.Count; 912 } 913 Remove(T element)914 public void Remove(T element) 915 { 916 var index = internalList.IndexOf(element); 917 if(index == -1) 918 { 919 throw new ArgumentException(); 920 } 921 922 internalList[index] = null; 923 } 924 RemoveAt(int index)925 public void RemoveAt(int index) 926 { 927 internalList[index] = null; 928 } 929 930 private readonly List<T> internalList; 931 } 932 933 private class QueueTransferDescriptor 934 { QueueTransferDescriptor(IBusController bus)935 public QueueTransferDescriptor(IBusController bus) 936 { 937 systemBus = bus; 938 Buffer = new uint[5]; 939 } 940 941 //future 64bit data structures support Fetch(ulong address)942 public void Fetch(ulong address) 943 { 944 //store address 945 memoryAddress = address; 946 947 //get data from memory 948 PhysNext = systemBus.ReadDoubleWord(address); 949 PhysAlternativeNext = systemBus.ReadDoubleWord(address + 0x04); 950 Token = systemBus.ReadDoubleWord(address + 0x08); 951 952 for(var i = 0u; i < Buffer.Length; i++) 953 { 954 Buffer[i] = systemBus.ReadDoubleWord(address + 0x0C + i * 4); 955 } 956 957 //extract fields 958 Next = PhysNext & ~(0x1fu); 959 NextTerminate = ((PhysNext & 0x01) != 0); 960 AlternativeNext = PhysAlternativeNext & ~(0x1fu); 961 AlternativeNextTerminate = ((PhysAlternativeNext & 0x01) != 0); 962 DataToggle = ((Token & (1u << 31)) != 0); 963 TotalBytesToTransfer = (Token >> 16) & 0x7fffu; 964 InterruptOnComplete = ((Token & (1u << 15)) != 0); 965 CurrentPage = (byte)((Token >> 12) & 0x07u); 966 ErrorCount = (byte)((Token >> 10) & 0x03u); 967 PID = (PIDCode)((Token >> 8) & 0x03u); 968 Status = (byte)(Token & 0xffu); 969 CurrentOffset = Buffer[0] & 0x0fffu; 970 Buffer[0] &= ~(0x0fffu); 971 } 972 FetchNext()973 public ulong FetchNext() 974 { 975 if(!NextTerminate) //if next one is normal td 976 { 977 memoryAddress = Next; 978 Fetch(Next); 979 return memoryAddress; 980 } 981 if(!AlternativeNextTerminate) //if next one is short packet 982 { 983 memoryAddress = AlternativeNext; 984 Fetch(AlternativeNext); 985 return memoryAddress; 986 } 987 return 0; 988 } 989 UpdateMemory()990 public void UpdateMemory() 991 { 992 //consolidate fields 993 PhysNext = Next | (NextTerminate ? 0x01u : 0x00u); 994 PhysAlternativeNext = AlternativeNext | (AlternativeNextTerminate ? 0x01u : 0x00u); 995 Token = (DataToggle ? 0 : (1u << 31)) | (TotalBytesToTransfer << 16) 996 | (InterruptOnComplete ? (1u << 15) : 0) | (uint)(CurrentPage << 12) 997 | (uint)(ErrorCount << 10) | ((uint)PID << 8) | (uint)Status; 998 999 //write memory 1000 systemBus.WriteDoubleWord(memoryAddress, PhysNext); 1001 systemBus.WriteDoubleWord(memoryAddress + 0x04, PhysAlternativeNext | 0x08); 1002 systemBus.WriteDoubleWord(memoryAddress + 0x08, Token); 1003 systemBus.WriteDoubleWord(memoryAddress + 0x0C, Buffer[0] | CurrentOffset); 1004 for(var i = 1u; i < Buffer.Length; i++) 1005 { 1006 systemBus.WriteDoubleWord(memoryAddress + 0x0C + i * 4, Buffer[i]); 1007 } 1008 } 1009 UpdateFromOverlay(QueueHeadOverlay overlay)1010 public void UpdateFromOverlay(QueueHeadOverlay overlay) 1011 { 1012 Next = overlay.NextPointer; 1013 NextTerminate = overlay.NextPointerTerminate; 1014 AlternativeNext = overlay.AlternateNextPointer; 1015 AlternativeNextTerminate = overlay.AlternateNextPointerTerminate; 1016 TotalBytesToTransfer = overlay.TotalBytesToTransfer; 1017 InterruptOnComplete = overlay.InterruptOnComplete; 1018 CurrentPage = overlay.CurrentPage; 1019 PID = overlay.PID; 1020 Status = overlay.Status; 1021 CurrentOffset = overlay.CurrentOffset; 1022 for(int i = 0; i < Buffer.Length; i++) 1023 { 1024 Buffer[i] = overlay.BufferPointer[i]; 1025 } 1026 } 1027 Processed()1028 public void Processed() 1029 { 1030 Status &= 0x7f; 1031 } 1032 1033 public uint PhysAlternativeNext { get; private set; } 1034 public byte ErrorCount { get; private set; } 1035 public byte Status { get; private set; } 1036 public uint CurrentOffset { get; private set; } 1037 public uint PhysNext { get; private set; } 1038 public bool AlternativeNextTerminate { get; private set; } 1039 public uint AlternativeNext { get; private set; } 1040 public bool NextTerminate { get; private set; } 1041 public uint Token { get; private set; } 1042 public uint Next { get; private set; } 1043 public bool DataToggle { get; private set; } 1044 public bool InterruptOnComplete { get; private set; } 1045 public byte CurrentPage { get; private set; } 1046 public PIDCode PID { get; private set; } 1047 public uint[] Buffer { get; private set; } 1048 1049 public uint TotalBytesToTransfer { get; set; } 1050 1051 private IBusController systemBus; 1052 private ulong memoryAddress; 1053 } 1054 1055 private class InterruptEnable 1056 { Clear()1057 public void Clear() 1058 { 1059 OnAsyncAdvanceEnable = false; 1060 HostSystemErrorEnable = false; 1061 FrameListRolloverEnable = false; 1062 PortChangeEnable = false; 1063 USBErrorEnable = false; 1064 Enable = false; 1065 } 1066 1067 public bool OnAsyncAdvanceEnable { get; set; } 1068 public bool HostSystemErrorEnable { get; set; } 1069 public bool FrameListRolloverEnable { get; set; } 1070 public bool PortChangeEnable { get; set; } 1071 public bool USBErrorEnable { get; set; } 1072 public bool Enable { get; set; } 1073 1074 public uint Value 1075 { 1076 get 1077 { 1078 return (uint)(OnAsyncAdvanceEnable ? 1 : 0) << 5 1079 | (uint)(HostSystemErrorEnable ? 1 : 0) << 4 1080 | (uint)(FrameListRolloverEnable ? 1 : 0) << 3 1081 | (uint)(PortChangeEnable ? 1 : 0) << 2 1082 | (uint)(USBErrorEnable ? 1 : 0) << 1 1083 | (uint)(Enable ? 1 : 0) << 0; 1084 } 1085 } 1086 } 1087 1088 // 1089 // TODO: 1090 // qh is spread over < address , address + 0x30 ) 1091 // all the check stuff should be redone not to read @ address multiple times 1092 // 1093 private class QueueHead 1094 { QueueHead(IBusController bus)1095 public QueueHead(IBusController bus) 1096 { 1097 Overlay = new QueueHeadOverlay(bus); 1098 TransferDescriptor = new QueueTransferDescriptor(bus); 1099 systemBus = bus; 1100 } 1101 Fetch()1102 public void Fetch() 1103 { 1104 link = systemBus.ReadDoubleWord(Address); 1105 staticEndpointState1 = systemBus.ReadDoubleWord(Address + 0x04); 1106 staticEndpointState2 = systemBus.ReadDoubleWord(Address + 0x08); 1107 CurrentTransferDescriptor = (uint)Address + 0x10u; 1108 1109 linkPointer = (uint)(link & ~(0x1f)); 1110 type = (byte)((link & 0x6) >> 1); 1111 terminate = ((link & 0x1) != 0); 1112 1113 DataToggleControl = ((staticEndpointState1 & 0x4000) != 0); 1114 EndpointSpeed = (EndpointSpeed)((staticEndpointState1 & 0x3000) >> 12); 1115 EndpointNumber = (byte)((staticEndpointState1 & 0xf00) >> 8); 1116 DeviceAddress = (byte)(staticEndpointState1 & 0x7f); 1117 1118 PortNumber = (byte)((staticEndpointState2 & 0x3F800000) >> 23); 1119 HubAddress = (byte)((staticEndpointState2 & 0x7F0000) >> 16); 1120 TransferDescriptor.Fetch(CurrentTransferDescriptor); 1121 Overlay.FillWithTransferDescriptor(TransferDescriptor, this); 1122 } 1123 GoToNextLink()1124 public bool GoToNextLink() 1125 { 1126 var val = (uint)(systemBus.ReadDoubleWord(Address) & ~(0x1f)); 1127 if((val != Address) && (val != 0)) 1128 { 1129 Address = val; 1130 return true; 1131 } 1132 return false; 1133 } 1134 Advance()1135 public void Advance() 1136 { 1137 CurrentTransferDescriptor = (uint)TransferDescriptor.FetchNext(); // get next transfer descriptor 1138 Overlay.FillWithTransferDescriptor(TransferDescriptor, this); // fill transfer descriptor with data from overlay 1139 } 1140 WriteBackTransferDescriptor()1141 public void WriteBackTransferDescriptor() 1142 { 1143 TransferDescriptor.UpdateFromOverlay(Overlay); 1144 TransferDescriptor.UpdateMemory(); 1145 } 1146 Processed()1147 public void Processed() 1148 { 1149 Overlay.Processed(); 1150 TransferDescriptor.Processed(); 1151 } 1152 StaticMemoryUpdate()1153 public void StaticMemoryUpdate() 1154 { 1155 link = linkPointer | ((uint)type << 1) | (terminate ? 1u : 0u); 1156 1157 //update RAM 1158 systemBus.WriteDoubleWord(Address + 0x0C, CurrentTransferDescriptor); 1159 systemBus.WriteDoubleWord(Address + 0x10, TransferDescriptor.PhysNext); 1160 systemBus.WriteDoubleWord(Address + 0x14, TransferDescriptor.PhysAlternativeNext | 0x08); 1161 systemBus.WriteDoubleWord(Address + 0x18, TransferDescriptor.Token); 1162 systemBus.WriteDoubleWord(Address + 0x1c, TransferDescriptor.Buffer[0] | TransferDescriptor.CurrentOffset); 1163 systemBus.WriteDoubleWord(Address + 0x20, TransferDescriptor.Buffer[1]); 1164 systemBus.WriteDoubleWord(Address + 0x24, TransferDescriptor.Buffer[2]); 1165 systemBus.WriteDoubleWord(Address + 0x28, TransferDescriptor.Buffer[3]); 1166 systemBus.WriteDoubleWord(Address + 0x2c, TransferDescriptor.Buffer[4]); 1167 } 1168 UpdateTotalBytesToTransfer(uint trasferredBytes)1169 public void UpdateTotalBytesToTransfer(uint trasferredBytes) 1170 { 1171 Overlay.TotalBytesToTransfer -= trasferredBytes; 1172 TransferDescriptor.TotalBytesToTransfer -= trasferredBytes; 1173 } 1174 1175 public ulong Address { get; set; } 1176 1177 public bool IsValid { get { return ((systemBus.ReadDoubleWord(Address) & 0x1) == 0); } } 1178 1179 public byte ElementName { get { return (byte)((systemBus.ReadDoubleWord(Address) & 0x6) >> 1); } } 1180 1181 public QueueHeadOverlay Overlay { get; private set; } 1182 1183 public QueueTransferDescriptor TransferDescriptor { get; private set; } 1184 1185 public bool DataToggleControl { get; private set; } 1186 1187 public EndpointSpeed EndpointSpeed { get; private set; } 1188 1189 public byte DeviceAddress { get; private set; } 1190 1191 public byte HubAddress { get; private set; } 1192 1193 public byte PortNumber { get; private set; } 1194 1195 public byte EndpointNumber { get; private set; } 1196 1197 public uint CurrentTransferDescriptor { get; private set; } 1198 1199 private readonly IBusController systemBus; 1200 private uint linkPointer; 1201 private byte type; 1202 private bool terminate; 1203 private uint link; 1204 private uint staticEndpointState1; 1205 private uint staticEndpointState2; 1206 } 1207 1208 private class QueueHeadOverlay 1209 { QueueHeadOverlay(IBusController bus)1210 public QueueHeadOverlay(IBusController bus) 1211 { 1212 systemBus = bus; 1213 BufferPointer = new uint[5]; 1214 } 1215 FillWithTransferDescriptor(QueueTransferDescriptor td, QueueHead qh)1216 public void FillWithTransferDescriptor(QueueTransferDescriptor td, QueueHead qh) 1217 { 1218 memoryAddress = qh.CurrentTransferDescriptor; 1219 NextPointer = td.Next; 1220 NextPointerTerminate = td.NextTerminate; 1221 AlternateNextPointer = td.AlternativeNext; 1222 AlternateNextPointerTerminate = td.AlternativeNextTerminate; 1223 TotalBytesToTransfer = td.TotalBytesToTransfer; 1224 InterruptOnComplete = td.InterruptOnComplete; 1225 CurrentPage = td.CurrentPage; 1226 errorCount = td.ErrorCount; 1227 PID = td.PID; 1228 token = td.Token; 1229 1230 CurrentOffset = td.CurrentOffset; 1231 Array.Copy(td.Buffer, BufferPointer, BufferPointer.Length); 1232 1233 if(qh.DataToggleControl) 1234 { 1235 dataToggle = td.DataToggle; 1236 } 1237 1238 Status = (qh.EndpointSpeed == EndpointSpeed.HighSpeed) ? 1239 (byte)((td.Status & (byte)0xFE) | (Status & (byte)0x01)) //preserve old ping bit 1240 : td.Status; 1241 } 1242 UpdateMemory()1243 public void UpdateMemory() 1244 { 1245 //consolidate fields 1246 physNext = NextPointer | (NextPointerTerminate ? 0x01u : 0x00u); 1247 physAlternatNext = AlternateNextPointer | (AlternateNextPointerTerminate ? 0x01u : 0x00u); 1248 token = (dataToggle ? (1u << 31) : 0) | (TotalBytesToTransfer << 16) 1249 | (InterruptOnComplete ? (1u << 15) : 0) | (uint)(CurrentPage << 12) 1250 | (uint)(errorCount << 10) | ((uint)PID << 8) | (uint)Status; 1251 CurrentOffset += TotalBytesToTransfer; 1252 1253 //write memory 1254 systemBus.WriteDoubleWord(memoryAddress, physNext); 1255 systemBus.WriteDoubleWord(memoryAddress + 0x04, physAlternatNext); 1256 systemBus.WriteDoubleWord(memoryAddress + 0x08, token); 1257 systemBus.WriteDoubleWord(memoryAddress + 0x0C, BufferPointer[0] | CurrentOffset); 1258 systemBus.WriteDoubleWord(memoryAddress + 0x10, BufferPointer[1]); 1259 systemBus.WriteDoubleWord(memoryAddress + 0x14, BufferPointer[2]); 1260 for(var i = 3u; i < BufferPointer.Length; i++) 1261 { 1262 systemBus.WriteDoubleWord(memoryAddress + 0x0C + i * 4, BufferPointer[i]); 1263 } 1264 } 1265 Processed()1266 public void Processed() 1267 { 1268 Status &= 0x7f; 1269 } 1270 1271 public uint NextPointer { get; private set; } 1272 public bool NextPointerTerminate { get; private set; } 1273 public uint AlternateNextPointer { get; private set; } 1274 public bool AlternateNextPointerTerminate { get; private set; } 1275 public uint TotalBytesToTransfer { get; set; } 1276 public bool InterruptOnComplete { get; private set; } 1277 public byte CurrentPage { get; private set; } 1278 public PIDCode PID { get; private set; } 1279 public byte Status { get; private set; } 1280 public uint[] BufferPointer { get; private set; } 1281 public uint CurrentOffset { get; private set; } 1282 1283 private readonly IBusController systemBus; 1284 private ulong memoryAddress; 1285 private bool dataToggle; 1286 private byte errorCount; 1287 private uint physNext; 1288 private uint physAlternatNext; 1289 private uint token; 1290 } 1291 1292 private enum EndpointSpeed 1293 { 1294 FullSpeed = 0, // 12 Mbs 1295 LowSpeed = 1, // 1.5 Mbs 1296 HighSpeed = 2, // 480 Mbs 1297 Reserved = 3 1298 } 1299 1300 private enum InterruptMask : uint 1301 { 1302 InterruptOnAsyncAdvance = (uint)(1 << 5), 1303 HostSystemError = (uint)(1 << 4), 1304 FrameListRollover = (uint)(1 << 3), 1305 PortChange = (uint)(1 << 2), 1306 USBError = (uint)(1 << 1), 1307 USBInterrupt = (uint)(1 << 0) 1308 } 1309 1310 private enum EhciUsbCommandMask : uint 1311 { 1312 InterruptOnAsyncAdvanceDoorbell = (1 << 6), 1313 AsynchronousScheduleEnable = (1 << 5), 1314 PeriodicScheduleEnable = (1 << 4), 1315 HostControllerReset = (1 << 1), 1316 RunStop = 1 1317 } 1318 1319 private enum EhciUsbStatusMask : uint 1320 { 1321 AsynchronousScheduleStatus = (1 << 15), 1322 PeriodicScheduleStatus = (1 << 14), 1323 Reclamation = (1 << 13), 1324 HCHalted = (1 << 12), 1325 InterruptOnAsyncAdvance = (1 << 5) 1326 } 1327 1328 private enum ControllerMode 1329 { 1330 Idle, 1331 Reserved, 1332 DeviceMode, 1333 HostMode 1334 } 1335 1336 private enum CapabilityRegisters : uint 1337 { 1338 CapabilityRegistersLength = 0x0, 1339 HCIVersionNumber = 0x2, 1340 StructuralParameters = 0x04, 1341 CompanionPortRouteDescription = 0x0C, 1342 } 1343 1344 private enum OperationalRegisters : uint 1345 { 1346 UsbCommand = 0x0, 1347 UsbStatus = 0x04, 1348 UsbInterruptEnable = 0x08, 1349 UsbFrameIndex = 0x0C, 1350 PeriodicListBaseAddress = 0x14, /* Frame List Base Address */ 1351 AsyncListAddress = 0x18, 1352 ConfiguredFlag = 0x40, 1353 } 1354 1355 //TODO: this looks like Tegra stuff, not generic EHCI 1356 private enum OtherRegisters : uint 1357 { 1358 UsbDCCParams = 0x124, 1359 UsbMode = 0x1A8, 1360 } 1361 1362 private enum PIDCode 1363 { 1364 Out = 0, 1365 In = 1, 1366 Setup = 2 1367 } 1368 1369 private enum DataDirection 1370 { 1371 HostToDevice = 0, 1372 DeviceToHost = 1 1373 } 1374 1375 private enum DeviceRequestType 1376 { 1377 GetStatus = 0, 1378 ClearFeature = 1, 1379 SetFeature = 3, 1380 SetAddress = 5, 1381 GetDescriptor = 6, 1382 SetDescriptor = 7, 1383 GetConfiguration = 8, 1384 SetConfiguration = 9, 1385 GetInterface = 10, 1386 SetInterFace = 11, 1387 SynchFrame = 12 1388 } 1389 } 1390 1391 public static class LongExtensions 1392 { InRange(this long value, long baseValue, uint length, out long shift)1393 public static bool InRange(this long value, long baseValue, uint length, out long shift) 1394 { 1395 shift = value - baseValue; 1396 return (shift >= 0 && shift < length); 1397 } 1398 } 1399 } 1400