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