xref: /reactos/drivers/usb/usbehci/usbehci.c (revision 7115d7ba)
1 /*
2  * PROJECT:     ReactOS USB EHCI Miniport Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBEHCI main driver functions
5  * COPYRIGHT:   Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbehci.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define NDEBUG_EHCI_TRACE
14 #include "dbg_ehci.h"
15 
16 USBPORT_REGISTRATION_PACKET RegPacket;
17 
18 static const UCHAR ClassicPeriod[8] = {
19     ENDPOINT_INTERRUPT_1ms - 1,
20     ENDPOINT_INTERRUPT_2ms - 1,
21     ENDPOINT_INTERRUPT_4ms - 1,
22     ENDPOINT_INTERRUPT_8ms - 1,
23     ENDPOINT_INTERRUPT_16ms - 1,
24     ENDPOINT_INTERRUPT_32ms - 1,
25     ENDPOINT_INTERRUPT_32ms - 1,
26     ENDPOINT_INTERRUPT_32ms - 1
27 };
28 
29 static const EHCI_PERIOD pTable[] = {
30     { ENDPOINT_INTERRUPT_1ms, 0x00, 0xFF },
31     { ENDPOINT_INTERRUPT_2ms, 0x00, 0x55 },
32     { ENDPOINT_INTERRUPT_2ms, 0x00, 0xAA },
33     { ENDPOINT_INTERRUPT_4ms, 0x00, 0x11 },
34     { ENDPOINT_INTERRUPT_4ms, 0x00, 0x44 },
35     { ENDPOINT_INTERRUPT_4ms, 0x00, 0x22 },
36     { ENDPOINT_INTERRUPT_4ms, 0x00, 0x88 },
37     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x01 },
38     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x10 },
39     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x04 },
40     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x40 },
41     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x02 },
42     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x20 },
43     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x08 },
44     { ENDPOINT_INTERRUPT_8ms, 0x00, 0x80 },
45     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x01 },
46     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x01 },
47     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x10 },
48     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x10 },
49     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x04 },
50     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x04 },
51     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x40 },
52     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x40 },
53     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x02 },
54     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x02 },
55     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x20 },
56     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x20 },
57     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x08 },
58     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x08 },
59     { ENDPOINT_INTERRUPT_16ms, 0x01, 0x80 },
60     { ENDPOINT_INTERRUPT_16ms, 0x02, 0x80 },
61     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x01 },
62     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x01 },
63     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x01 },
64     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x01 },
65     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x10 },
66     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x10 },
67     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x10 },
68     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x10 },
69     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x04 },
70     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x04 },
71     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x04 },
72     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x04 },
73     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x40 },
74     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x40 },
75     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x40 },
76     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x40 },
77     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x02 },
78     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x02 },
79     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x02 },
80     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x02 },
81     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x20 },
82     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x20 },
83     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x20 },
84     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x20 },
85     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x08 },
86     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x08 },
87     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x08 },
88     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x08 },
89     { ENDPOINT_INTERRUPT_32ms, 0x03, 0x80 },
90     { ENDPOINT_INTERRUPT_32ms, 0x05, 0x80 },
91     { ENDPOINT_INTERRUPT_32ms, 0x04, 0x80 },
92     { ENDPOINT_INTERRUPT_32ms, 0x06, 0x80 },
93     { 0x00, 0x00, 0x00 }
94 };
95 C_ASSERT(RTL_NUMBER_OF(pTable) == INTERRUPT_ENDPOINTs + 1);
96 
97 static const UCHAR Balance[] = {
98     0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30,
99     1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31
100 };
101 C_ASSERT(RTL_NUMBER_OF(Balance) == EHCI_FRAMES);
102 
103 static const UCHAR LinkTable[] = {
104     255, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,  9, 9,
105     10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19,
106     20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29,
107     30, 30, 0
108 };
109 C_ASSERT(RTL_NUMBER_OF(LinkTable) == INTERRUPT_ENDPOINTs + 1);
110 
111 PEHCI_HCD_TD
112 NTAPI
113 EHCI_AllocTd(IN PEHCI_EXTENSION EhciExtension,
114              IN PEHCI_ENDPOINT EhciEndpoint)
115 {
116     PEHCI_HCD_TD TD;
117     ULONG ix;
118 
119     DPRINT_EHCI("EHCI_AllocTd: ... \n");
120 
121     if (EhciEndpoint->MaxTDs == 0)
122     {
123         RegPacket.UsbPortBugCheck(EhciExtension);
124         return NULL;
125     }
126 
127     TD = EhciEndpoint->FirstTD;
128 
129     for (ix = 1; TD->TdFlags & EHCI_HCD_TD_FLAG_ALLOCATED; ix++)
130     {
131         TD += 1;
132 
133         if (ix >= EhciEndpoint->MaxTDs)
134         {
135             RegPacket.UsbPortBugCheck(EhciExtension);
136             return NULL;
137         }
138     }
139 
140     TD->TdFlags |= EHCI_HCD_TD_FLAG_ALLOCATED;
141 
142     EhciEndpoint->RemainTDs--;
143 
144     return TD;
145 }
146 
147 PEHCI_HCD_QH
148 NTAPI
149 EHCI_InitializeQH(IN PEHCI_EXTENSION EhciExtension,
150                   IN PEHCI_ENDPOINT EhciEndpoint,
151                   IN PEHCI_HCD_QH QH,
152                   IN ULONG QhPA)
153 {
154     PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
155     ULONG DeviceSpeed;
156 
157     DPRINT_EHCI("EHCI_InitializeQH: EhciEndpoint - %p, QH - %p, QhPA - %p\n",
158                 EhciEndpoint,
159                 QH,
160                 QhPA);
161 
162     EndpointProperties = &EhciEndpoint->EndpointProperties;
163 
164     RtlZeroMemory(QH, sizeof(EHCI_HCD_QH));
165 
166     ASSERT((QhPA & ~LINK_POINTER_MASK) == 0);
167 
168     QH->sqh.PhysicalAddress = QhPA;
169 
170     QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress;
171     QH->sqh.HwQH.EndpointParams.EndpointNumber = EndpointProperties->EndpointAddress;
172 
173     DeviceSpeed = EndpointProperties->DeviceSpeed;
174 
175     switch (DeviceSpeed)
176     {
177         case UsbLowSpeed:
178             QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_LOW_SPEED;
179             break;
180 
181         case UsbFullSpeed:
182             QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_FULL_SPEED;
183             break;
184 
185         case UsbHighSpeed:
186             QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_HIGH_SPEED;
187             break;
188 
189         default:
190             DPRINT1("EHCI_InitializeQH: Unknown DeviceSpeed - %x\n", DeviceSpeed);
191             ASSERT(FALSE);
192             break;
193     }
194 
195     QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize;
196     QH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1;
197 
198     if (DeviceSpeed == UsbHighSpeed)
199     {
200         QH->sqh.HwQH.EndpointCaps.HubAddr = 0;
201         QH->sqh.HwQH.EndpointCaps.PortNumber = 0;
202     }
203     else
204     {
205         QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr;
206         QH->sqh.HwQH.EndpointCaps.PortNumber = EndpointProperties->PortNumber;
207 
208         if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
209             QH->sqh.HwQH.EndpointParams.ControlEndpointFlag = 1;
210     }
211 
212     QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
213     QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
214 
215     QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
216                                           EHCI_TOKEN_STATUS_HALTED);
217 
218     return QH;
219 }
220 
221 MPSTATUS
222 NTAPI
223 EHCI_OpenBulkOrControlEndpoint(IN PEHCI_EXTENSION EhciExtension,
224                                IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
225                                IN PEHCI_ENDPOINT EhciEndpoint,
226                                IN BOOLEAN IsControl)
227 {
228     PEHCI_HCD_QH QH;
229     ULONG QhPA;
230     PEHCI_HCD_TD TdVA;
231     ULONG TdPA;
232     PEHCI_HCD_TD TD;
233     ULONG TdCount;
234     ULONG ix;
235 
236     DPRINT("EHCI_OpenBulkOrControlEndpoint: EhciEndpoint - %p, IsControl - %x\n",
237            EhciEndpoint,
238            IsControl);
239 
240     InitializeListHead(&EhciEndpoint->ListTDs);
241 
242     EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA;
243     EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA;
244 
245     RtlZeroMemory(EhciEndpoint->DmaBufferVA, sizeof(EHCI_HCD_TD));
246 
247     QH = (PEHCI_HCD_QH)EhciEndpoint->DmaBufferVA + 1;
248     QhPA = EhciEndpoint->DmaBufferPA + sizeof(EHCI_HCD_TD);
249 
250     EhciEndpoint->FirstTD = (PEHCI_HCD_TD)(QH + 1);
251 
252     TdCount = (EndpointProperties->BufferLength -
253                (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) /
254                sizeof(EHCI_HCD_TD);
255 
256     if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
257         EhciEndpoint->EndpointStatus |= USBPORT_ENDPOINT_CONTROL;
258 
259     EhciEndpoint->MaxTDs = TdCount;
260     EhciEndpoint->RemainTDs = TdCount;
261 
262     TdVA = EhciEndpoint->FirstTD;
263     TdPA = QhPA + sizeof(EHCI_HCD_QH);
264 
265     for (ix = 0; ix < TdCount; ix++)
266     {
267         DPRINT_EHCI("EHCI_OpenBulkOrControlEndpoint: TdVA - %p, TdPA - %p\n",
268                     TdVA,
269                     TdPA);
270 
271         RtlZeroMemory(TdVA, sizeof(EHCI_HCD_TD));
272 
273         ASSERT((TdPA & ~LINK_POINTER_MASK) == 0);
274 
275         TdVA->PhysicalAddress = TdPA;
276         TdVA->EhciEndpoint = EhciEndpoint;
277         TdVA->EhciTransfer = NULL;
278 
279         TdPA += sizeof(EHCI_HCD_TD);
280         TdVA += 1;
281     }
282 
283     EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension,
284                                          EhciEndpoint,
285                                          QH,
286                                          QhPA);
287 
288     if (IsControl)
289     {
290         QH->sqh.HwQH.EndpointParams.DataToggleControl = 1;
291         EhciEndpoint->HcdHeadP = NULL;
292     }
293     else
294     {
295         QH->sqh.HwQH.EndpointParams.DataToggleControl = 0;
296     }
297 
298     TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
299 
300     if (!TD)
301         return MP_STATUS_NO_RESOURCES;
302 
303     TD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY;
304     TD->HwTD.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
305 
306     TD->HwTD.NextTD = TERMINATE_POINTER;
307     TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
308 
309     TD->NextHcdTD = NULL;
310     TD->AltNextHcdTD = NULL;
311 
312     EhciEndpoint->HcdTailP = TD;
313     EhciEndpoint->HcdHeadP = TD;
314 
315     QH->sqh.HwQH.CurrentTD = TD->PhysicalAddress;
316     QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
317     QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
318 
319     QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
320     QH->sqh.HwQH.Token.TransferBytes = 0;
321 
322     return MP_STATUS_SUCCESS;
323 }
324 
325 MPSTATUS
326 NTAPI
327 EHCI_OpenInterruptEndpoint(IN PEHCI_EXTENSION EhciExtension,
328                            IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
329                            IN PEHCI_ENDPOINT EhciEndpoint)
330 {
331     PEHCI_HCD_QH QH;
332     ULONG QhPA;
333     PEHCI_HCD_TD FirstTD;
334     ULONG FirstTdPA;
335     PEHCI_HCD_TD TD;
336     PEHCI_HCD_TD DummyTD;
337     ULONG TdCount;
338     ULONG ix;
339     const EHCI_PERIOD * PeriodTable = NULL;
340     ULONG ScheduleOffset;
341     ULONG Idx = 0;
342     UCHAR Period;
343 
344     DPRINT("EHCI_OpenInterruptEndpoint: EhciExtension - %p, EndpointProperties - %p, EhciEndpoint - %p\n",
345            EhciExtension,
346            EndpointProperties,
347            EhciEndpoint);
348 
349     Period = EndpointProperties->Period;
350     ScheduleOffset = EndpointProperties->ScheduleOffset;
351 
352     ASSERT(Period < (INTERRUPT_ENDPOINTs + 1));
353 
354     while (!(Period & 1))
355     {
356         Idx++;
357         Period >>= 1;
358     }
359 
360     ASSERT(Idx < 8);
361 
362     InitializeListHead(&EhciEndpoint->ListTDs);
363 
364     if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
365     {
366         PeriodTable = &pTable[ClassicPeriod[Idx] + ScheduleOffset];
367         EhciEndpoint->PeriodTable = PeriodTable;
368 
369         DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, ScheduleMask - %X, Index - %X\n",
370                EhciEndpoint,
371                PeriodTable->ScheduleMask,
372                ClassicPeriod[Idx]);
373 
374         EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[PeriodTable->PeriodIdx];
375     }
376     else
377     {
378         EhciEndpoint->PeriodTable = NULL;
379 
380         DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, Index - %X\n",
381                EhciEndpoint,
382                ClassicPeriod[Idx]);
383 
384         EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[ClassicPeriod[Idx] +
385                                                              ScheduleOffset];
386     }
387 
388     EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA;
389     EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA;
390 
391     RtlZeroMemory((PVOID)EndpointProperties->BufferVA, sizeof(EHCI_HCD_TD));
392 
393     QH = (PEHCI_HCD_QH)(EndpointProperties->BufferVA + sizeof(EHCI_HCD_TD));
394     QhPA = EndpointProperties->BufferPA + sizeof(EHCI_HCD_TD);
395 
396     FirstTD = (PEHCI_HCD_TD)(EndpointProperties->BufferVA +
397                              sizeof(EHCI_HCD_TD) +
398                              sizeof(EHCI_HCD_QH));
399 
400     FirstTdPA = EndpointProperties->BufferPA +
401                 sizeof(EHCI_HCD_TD) +
402                 sizeof(EHCI_HCD_QH);
403 
404     TdCount = (EndpointProperties->BufferLength -
405                (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) /
406                sizeof(EHCI_HCD_TD);
407 
408     ASSERT(TdCount >= EHCI_MAX_INTERRUPT_TD_COUNT + 1);
409 
410     EhciEndpoint->FirstTD = FirstTD;
411     EhciEndpoint->MaxTDs = TdCount;
412 
413     for (ix = 0; ix < TdCount; ix++)
414     {
415         TD = EhciEndpoint->FirstTD + ix;
416 
417         RtlZeroMemory(TD, sizeof(EHCI_HCD_TD));
418 
419         ASSERT((FirstTdPA & ~LINK_POINTER_MASK) == 0);
420 
421         TD->PhysicalAddress = FirstTdPA;
422         TD->EhciEndpoint = EhciEndpoint;
423         TD->EhciTransfer = NULL;
424 
425         FirstTdPA += sizeof(EHCI_HCD_TD);
426     }
427 
428     EhciEndpoint->RemainTDs = TdCount;
429 
430     EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension,
431                                          EhciEndpoint,
432                                          QH,
433                                          QhPA);
434 
435     if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
436     {
437         QH->sqh.HwQH.EndpointCaps.InterruptMask = PeriodTable->ScheduleMask;
438     }
439     else
440     {
441         QH->sqh.HwQH.EndpointCaps.InterruptMask =
442         EndpointProperties->InterruptScheduleMask;
443 
444         QH->sqh.HwQH.EndpointCaps.SplitCompletionMask =
445         EndpointProperties->SplitCompletionMask;
446     }
447 
448     DummyTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
449 
450     DummyTD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY;
451     DummyTD->NextHcdTD = NULL;
452     DummyTD->AltNextHcdTD = NULL;
453 
454     DummyTD->HwTD.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE;
455 
456     DummyTD->HwTD.NextTD = TERMINATE_POINTER;
457     DummyTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
458 
459     EhciEndpoint->HcdTailP = DummyTD;
460     EhciEndpoint->HcdHeadP = DummyTD;
461 
462     QH->sqh.HwQH.CurrentTD = DummyTD->PhysicalAddress;
463     QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
464     QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
465 
466     QH->sqh.HwQH.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE;
467     QH->sqh.HwQH.Token.TransferBytes = 0;
468 
469     return MP_STATUS_SUCCESS;
470 }
471 
472 MPSTATUS
473 NTAPI
474 EHCI_OpenHsIsoEndpoint(IN PEHCI_EXTENSION EhciExtension,
475                        IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
476                        IN PEHCI_ENDPOINT EhciEndpoint)
477 {
478     DPRINT1("EHCI_OpenHsIsoEndpoint: UNIMPLEMENTED. FIXME\n");
479     return MP_STATUS_NOT_SUPPORTED;
480 }
481 
482 MPSTATUS
483 NTAPI
484 EHCI_OpenIsoEndpoint(IN PEHCI_EXTENSION EhciExtension,
485                      IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
486                      IN PEHCI_ENDPOINT EhciEndpoint)
487 {
488     DPRINT1("EHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n");
489     return MP_STATUS_NOT_SUPPORTED;
490 }
491 
492 MPSTATUS
493 NTAPI
494 EHCI_OpenEndpoint(IN PVOID ehciExtension,
495                   IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
496                   IN PVOID ehciEndpoint)
497 {
498     PEHCI_EXTENSION EhciExtension = ehciExtension;
499     PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
500     ULONG TransferType;
501     MPSTATUS MPStatus;
502 
503     DPRINT("EHCI_OpenEndpoint: ... \n");
504 
505     RtlCopyMemory(&EhciEndpoint->EndpointProperties,
506                   EndpointProperties,
507                   sizeof(EhciEndpoint->EndpointProperties));
508 
509     TransferType = EndpointProperties->TransferType;
510 
511     switch (TransferType)
512     {
513         case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
514             if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
515             {
516                 MPStatus = EHCI_OpenHsIsoEndpoint(EhciExtension,
517                                                   EndpointProperties,
518                                                   EhciEndpoint);
519             }
520             else
521             {
522                 MPStatus = EHCI_OpenIsoEndpoint(EhciExtension,
523                                                 EndpointProperties,
524                                                 EhciEndpoint);
525             }
526 
527             break;
528 
529         case USBPORT_TRANSFER_TYPE_CONTROL:
530             MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension,
531                                                       EndpointProperties,
532                                                       EhciEndpoint,
533                                                       TRUE);
534             break;
535 
536         case USBPORT_TRANSFER_TYPE_BULK:
537             MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension,
538                                                       EndpointProperties,
539                                                       EhciEndpoint,
540                                                       FALSE);
541             break;
542 
543         case USBPORT_TRANSFER_TYPE_INTERRUPT:
544             MPStatus = EHCI_OpenInterruptEndpoint(EhciExtension,
545                                                   EndpointProperties,
546                                                   EhciEndpoint);
547             break;
548 
549         default:
550             MPStatus = MP_STATUS_NOT_SUPPORTED;
551             break;
552     }
553 
554     return MPStatus;
555 }
556 
557 MPSTATUS
558 NTAPI
559 EHCI_ReopenEndpoint(IN PVOID ehciExtension,
560                     IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
561                     IN PVOID ehciEndpoint)
562 {
563     PEHCI_ENDPOINT EhciEndpoint;
564     ULONG TransferType;
565     PEHCI_HCD_QH QH;
566     MPSTATUS MPStatus;
567 
568     EhciEndpoint = ehciEndpoint;
569 
570     TransferType = EndpointProperties->TransferType;
571 
572     DPRINT("EHCI_ReopenEndpoint: EhciEndpoint - %p, TransferType - %x\n",
573            EhciEndpoint,
574            TransferType);
575 
576     switch (TransferType)
577     {
578         case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
579             if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
580             {
581                 DPRINT1("EHCI_ReopenEndpoint: HS Iso. UNIMPLEMENTED. FIXME\n");
582                 MPStatus = MP_STATUS_NOT_SUPPORTED;
583             }
584             else
585             {
586                 DPRINT1("EHCI_ReopenEndpoint: Iso. UNIMPLEMENTED. FIXME\n");
587                 MPStatus = MP_STATUS_NOT_SUPPORTED;
588             }
589 
590             break;
591 
592         case USBPORT_TRANSFER_TYPE_CONTROL:
593         case USBPORT_TRANSFER_TYPE_BULK:
594         case USBPORT_TRANSFER_TYPE_INTERRUPT:
595             RtlCopyMemory(&EhciEndpoint->EndpointProperties,
596                           EndpointProperties,
597                           sizeof(EhciEndpoint->EndpointProperties));
598 
599             QH = EhciEndpoint->QH;
600 
601             QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress;
602             QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize;
603 
604             QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr;
605 
606             break;
607 
608         default:
609             DPRINT1("EHCI_ReopenEndpoint: Unknown TransferType\n");
610             MPStatus = MP_STATUS_SUCCESS;
611             break;
612     }
613 
614     return MPStatus;
615 }
616 
617 VOID
618 NTAPI
619 EHCI_QueryEndpointRequirements(IN PVOID ehciExtension,
620                                IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
621                                IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements)
622 {
623     ULONG TransferType;
624 
625     DPRINT("EHCI_QueryEndpointRequirements: ... \n");
626 
627     TransferType = EndpointProperties->TransferType;
628 
629     switch (TransferType)
630     {
631         case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
632             DPRINT("EHCI_QueryEndpointRequirements: IsoTransfer\n");
633 
634             if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
635             {
636                 EndpointRequirements->HeaderBufferSize = EHCI_MAX_HS_ISO_HEADER_BUFFER_SIZE;
637                 EndpointRequirements->MaxTransferSize = EHCI_MAX_HS_ISO_TRANSFER_SIZE;
638             }
639             else
640             {
641                 EndpointRequirements->HeaderBufferSize = EHCI_MAX_FS_ISO_HEADER_BUFFER_SIZE;
642                 EndpointRequirements->MaxTransferSize = EHCI_MAX_FS_ISO_TRANSFER_SIZE;
643             }
644             break;
645 
646         case USBPORT_TRANSFER_TYPE_CONTROL:
647             DPRINT("EHCI_QueryEndpointRequirements: ControlTransfer\n");
648             EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
649                                                      sizeof(EHCI_HCD_QH) +
650                                                      EHCI_MAX_CONTROL_TD_COUNT * sizeof(EHCI_HCD_TD);
651 
652             EndpointRequirements->MaxTransferSize = EHCI_MAX_CONTROL_TRANSFER_SIZE;
653             break;
654 
655         case USBPORT_TRANSFER_TYPE_BULK:
656             DPRINT("EHCI_QueryEndpointRequirements: BulkTransfer\n");
657             EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
658                                                      sizeof(EHCI_HCD_QH) +
659                                                      EHCI_MAX_BULK_TD_COUNT * sizeof(EHCI_HCD_TD);
660 
661             EndpointRequirements->MaxTransferSize = EHCI_MAX_BULK_TRANSFER_SIZE;
662             break;
663 
664         case USBPORT_TRANSFER_TYPE_INTERRUPT:
665             DPRINT("EHCI_QueryEndpointRequirements: InterruptTransfer\n");
666             EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
667                                                      sizeof(EHCI_HCD_QH) +
668                                                      EHCI_MAX_INTERRUPT_TD_COUNT * sizeof(EHCI_HCD_TD);
669 
670             EndpointRequirements->MaxTransferSize = EHCI_MAX_INTERRUPT_TRANSFER_SIZE;
671             break;
672 
673         default:
674             DPRINT1("EHCI_QueryEndpointRequirements: Unknown TransferType - %x\n",
675                     TransferType);
676             DbgBreakPoint();
677             break;
678     }
679 }
680 
681 VOID
682 NTAPI
683 EHCI_DisablePeriodicList(IN PEHCI_EXTENSION EhciExtension)
684 {
685     PEHCI_HW_REGISTERS OperationalRegs;
686     EHCI_USB_COMMAND Command;
687 
688     DPRINT("EHCI_DisablePeriodicList: ... \n");
689 
690     if (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT)
691     {
692         OperationalRegs = EhciExtension->OperationalRegs;
693 
694         Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
695         Command.PeriodicEnable = 0;
696         WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
697     }
698 }
699 
700 VOID
701 NTAPI
702 EHCI_CloseEndpoint(IN PVOID ehciExtension,
703                    IN PVOID ehciEndpoint,
704                    IN BOOLEAN DisablePeriodic)
705 {
706     PEHCI_EXTENSION EhciExtension = ehciExtension;
707     PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
708     ULONG TransferType;
709 
710     DPRINT1("EHCI_CloseEndpoint: EhciEndpoint - %p, DisablePeriodic - %X\n",
711             EhciEndpoint,
712             DisablePeriodic);
713 
714     if (DisablePeriodic)
715     {
716         TransferType = EhciEndpoint->EndpointProperties.TransferType;
717 
718         if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS ||
719             TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
720         {
721             EHCI_DisablePeriodicList(EhciExtension);
722         }
723     }
724 }
725 
726 PEHCI_STATIC_QH
727 NTAPI
728 EHCI_GetQhForFrame(IN PEHCI_EXTENSION EhciExtension,
729                    IN ULONG FrameIdx)
730 {
731     //DPRINT_EHCI("EHCI_GetQhForFrame: FrameIdx - %x, Balance[FrameIdx] - %x\n",
732     //            FrameIdx,
733     //            Balance[FrameIdx & 0x1F]);
734 
735     return EhciExtension->PeriodicHead[Balance[FrameIdx & (EHCI_FRAMES - 1)]];
736 }
737 
738 PEHCI_HCD_QH
739 NTAPI
740 EHCI_GetDummyQhForFrame(IN PEHCI_EXTENSION EhciExtension,
741                         IN ULONG Idx)
742 {
743     return (PEHCI_HCD_QH)((ULONG_PTR)EhciExtension->IsoDummyQHListVA +
744                           Idx * sizeof(EHCI_HCD_QH));
745 }
746 
747 VOID
748 NTAPI
749 EHCI_AlignHwStructure(IN PEHCI_EXTENSION EhciExtension,
750                       IN PULONG PhysicalAddress,
751                       IN PULONG_PTR VirtualAddress,
752                       IN ULONG Alignment)
753 {
754     ULONG PAddress;
755     ULONG NewPAddress;
756     ULONG_PTR VAddress;
757 
758     //DPRINT_EHCI("EHCI_AlignHwStructure: *PhysicalAddress - %X, *VirtualAddress - %X, Alignment - %x\n",
759     //             *PhysicalAddress,
760     //             *VirtualAddress,
761     //             Alignment);
762 
763     PAddress = *PhysicalAddress;
764     VAddress = *VirtualAddress;
765 
766     NewPAddress = (ULONG)(ULONG_PTR)PAGE_ALIGN(*PhysicalAddress + Alignment - 1);
767 
768     if (NewPAddress != (ULONG)(ULONG_PTR)PAGE_ALIGN(*PhysicalAddress))
769     {
770         VAddress += NewPAddress - PAddress;
771         PAddress = NewPAddress;
772 
773         DPRINT("EHCI_AlignHwStructure: VAddress - %X, PAddress - %X\n",
774                VAddress,
775                PAddress);
776     }
777 
778     *VirtualAddress = VAddress;
779     *PhysicalAddress = PAddress;
780 }
781 
782 VOID
783 NTAPI
784 EHCI_AddDummyQHs(IN PEHCI_EXTENSION EhciExtension)
785 {
786     PEHCI_HC_RESOURCES HcResourcesVA;
787     PEHCI_HCD_QH DummyQH;
788     ULONG DummyQhPA;
789     EHCI_QH_EP_PARAMS EndpointParams;
790     EHCI_LINK_POINTER PAddress;
791     ULONG Frame;
792 
793     DPRINT("EHCI_AddDummyQueueHeads: EhciExtension - %p\n", EhciExtension);
794 
795     HcResourcesVA = EhciExtension->HcResourcesVA;
796 
797     DummyQH = EhciExtension->IsoDummyQHListVA;
798     DummyQhPA = EhciExtension->IsoDummyQHListPA;
799 
800     for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++)
801     {
802         RtlZeroMemory(DummyQH, sizeof(EHCI_HCD_QH));
803 
804         PAddress.AsULONG = HcResourcesVA->PeriodicFrameList[Frame];
805 
806         DummyQH->sqh.HwQH.HorizontalLink.AsULONG = PAddress.AsULONG;
807         DummyQH->sqh.HwQH.CurrentTD = 0;
808         DummyQH->sqh.HwQH.NextTD = TERMINATE_POINTER;
809         DummyQH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
810 
811         EndpointParams = DummyQH->sqh.HwQH.EndpointParams;
812         EndpointParams.DeviceAddress = 0;
813         EndpointParams.EndpointSpeed = 0;
814         EndpointParams.MaximumPacketLength = EHCI_DUMMYQH_MAX_PACKET_LENGTH;
815         DummyQH->sqh.HwQH.EndpointParams = EndpointParams;
816 
817         DummyQH->sqh.HwQH.EndpointCaps.AsULONG = 0;
818         DummyQH->sqh.HwQH.EndpointCaps.InterruptMask = 0;
819         DummyQH->sqh.HwQH.EndpointCaps.SplitCompletionMask = 0;
820         DummyQH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1;
821 
822         DummyQH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
823 
824         DummyQH->sqh.PhysicalAddress = DummyQhPA;
825         DummyQH->sqh.StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame);
826 
827         PAddress.AsULONG = DummyQhPA;
828         PAddress.Reserved = 0;
829         PAddress.Type = EHCI_LINK_TYPE_QH;
830 
831         HcResourcesVA->PeriodicFrameList[Frame] = PAddress.AsULONG;
832 
833         DummyQH++;
834         DummyQhPA += sizeof(EHCI_HCD_QH);
835     }
836 }
837 
838 VOID
839 NTAPI
840 EHCI_InitializeInterruptSchedule(IN PEHCI_EXTENSION EhciExtension)
841 {
842     PEHCI_STATIC_QH StaticQH;
843     ULONG ix;
844 
845     DPRINT("EHCI_InitializeInterruptSchedule: ... \n");
846 
847     for (ix = 0; ix < INTERRUPT_ENDPOINTs; ix++)
848     {
849         StaticQH = EhciExtension->PeriodicHead[ix];
850 
851         StaticQH->HwQH.EndpointParams.HeadReclamationListFlag = 0;
852         StaticQH->HwQH.NextTD |= TERMINATE_POINTER;
853         StaticQH->HwQH.Token.Status |= (UCHAR)EHCI_TOKEN_STATUS_HALTED;
854     }
855 
856     for (ix = 1; ix < INTERRUPT_ENDPOINTs; ix++)
857     {
858         StaticQH = EhciExtension->PeriodicHead[ix];
859 
860         StaticQH->PrevHead = NULL;
861         StaticQH->NextHead = (PEHCI_HCD_QH)EhciExtension->PeriodicHead[LinkTable[ix]];
862 
863         StaticQH->HwQH.HorizontalLink.AsULONG =
864             EhciExtension->PeriodicHead[LinkTable[ix]]->PhysicalAddress;
865 
866         StaticQH->HwQH.HorizontalLink.Type = EHCI_LINK_TYPE_QH;
867         StaticQH->HwQH.EndpointCaps.InterruptMask = 0xFF;
868 
869         StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC;
870 
871         if (ix < (ENDPOINT_INTERRUPT_8ms - 1))
872             StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC_FAST;
873     }
874 
875     EhciExtension->PeriodicHead[0]->HwQH.HorizontalLink.Terminate = 1;
876 
877     EhciExtension->PeriodicHead[0]->QhFlags |= (EHCI_QH_FLAG_STATIC |
878                                                 EHCI_QH_FLAG_STATIC_FAST);
879 }
880 
881 MPSTATUS
882 NTAPI
883 EHCI_InitializeSchedule(IN PEHCI_EXTENSION EhciExtension,
884                         IN ULONG_PTR BaseVA,
885                         IN ULONG BasePA)
886 {
887     PEHCI_HW_REGISTERS OperationalRegs;
888     PEHCI_HC_RESOURCES HcResourcesVA;
889     ULONG HcResourcesPA;
890     PEHCI_STATIC_QH AsyncHead;
891     ULONG AsyncHeadPA;
892     PEHCI_STATIC_QH PeriodicHead;
893     ULONG PeriodicHeadPA;
894     PEHCI_STATIC_QH StaticQH;
895     EHCI_LINK_POINTER NextLink;
896     EHCI_LINK_POINTER StaticHeadPA;
897     ULONG Frame;
898     ULONG ix;
899 
900     DPRINT("EHCI_InitializeSchedule: BaseVA - %p, BasePA - %p\n",
901            BaseVA,
902            BasePA);
903 
904     OperationalRegs = EhciExtension->OperationalRegs;
905 
906     HcResourcesVA = (PEHCI_HC_RESOURCES)BaseVA;
907     HcResourcesPA = BasePA;
908 
909     EhciExtension->HcResourcesVA = HcResourcesVA;
910     EhciExtension->HcResourcesPA = BasePA;
911 
912     /* Asynchronous Schedule */
913 
914     AsyncHead = &HcResourcesVA->AsyncHead;
915     AsyncHeadPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, AsyncHead);
916 
917     RtlZeroMemory(AsyncHead, sizeof(EHCI_STATIC_QH));
918 
919     NextLink.AsULONG = AsyncHeadPA;
920     NextLink.Type = EHCI_LINK_TYPE_QH;
921 
922     AsyncHead->HwQH.HorizontalLink = NextLink;
923     AsyncHead->HwQH.EndpointParams.HeadReclamationListFlag = 1;
924     AsyncHead->HwQH.EndpointCaps.PipeMultiplier = 1;
925     AsyncHead->HwQH.NextTD |= TERMINATE_POINTER;
926     AsyncHead->HwQH.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_HALTED;
927 
928     AsyncHead->PhysicalAddress = AsyncHeadPA;
929     AsyncHead->PrevHead = AsyncHead->NextHead = (PEHCI_HCD_QH)AsyncHead;
930 
931     EhciExtension->AsyncHead = AsyncHead;
932 
933     /* Periodic Schedule */
934 
935     PeriodicHead = &HcResourcesVA->PeriodicHead[0];
936     PeriodicHeadPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, PeriodicHead[0]);
937 
938     for (ix = 0; ix < (INTERRUPT_ENDPOINTs + 1); ix++)
939     {
940         EHCI_AlignHwStructure(EhciExtension,
941                               &PeriodicHeadPA,
942                               (PULONG_PTR)&PeriodicHead,
943                               80);
944 
945         EhciExtension->PeriodicHead[ix] = PeriodicHead;
946         EhciExtension->PeriodicHead[ix]->PhysicalAddress = PeriodicHeadPA;
947 
948         PeriodicHead += 1;
949         PeriodicHeadPA += sizeof(EHCI_STATIC_QH);
950     }
951 
952     EHCI_InitializeInterruptSchedule(EhciExtension);
953 
954     for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++)
955     {
956         StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame);
957 
958         StaticHeadPA.AsULONG = StaticQH->PhysicalAddress;
959         StaticHeadPA.Type = EHCI_LINK_TYPE_QH;
960 
961         //DPRINT_EHCI("EHCI_InitializeSchedule: StaticHeadPA[%x] - %X\n",
962         //            Frame,
963         //            StaticHeadPA);
964 
965         HcResourcesVA->PeriodicFrameList[Frame] = StaticHeadPA.AsULONG;
966     }
967 
968     EhciExtension->IsoDummyQHListVA = &HcResourcesVA->IsoDummyQH[0];
969     EhciExtension->IsoDummyQHListPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, IsoDummyQH[0]);
970 
971     EHCI_AddDummyQHs(EhciExtension);
972 
973     WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase,
974                          EhciExtension->HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, PeriodicFrameList));
975 
976     WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase,
977                          NextLink.AsULONG);
978 
979     return MP_STATUS_SUCCESS;
980 }
981 
982 MPSTATUS
983 NTAPI
984 EHCI_InitializeHardware(IN PEHCI_EXTENSION EhciExtension)
985 {
986     PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters;
987     PEHCI_HW_REGISTERS OperationalRegs;
988     EHCI_USB_COMMAND Command;
989     LARGE_INTEGER EndTime;
990     LARGE_INTEGER CurrentTime;
991     EHCI_HC_STRUCTURAL_PARAMS StructuralParams;
992 
993     DPRINT("EHCI_InitializeHardware: ... \n");
994 
995     OperationalRegs = EhciExtension->OperationalRegs;
996     CapabilityRegisters = EhciExtension->CapabilityRegisters;
997 
998     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
999     Command.Reset = 1;
1000     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1001 
1002     KeQuerySystemTime(&EndTime);
1003     EndTime.QuadPart += 100 * 10000; // 100 msec
1004 
1005     DPRINT("EHCI_InitializeHardware: Start reset ... \n");
1006 
1007     while (TRUE)
1008     {
1009         KeQuerySystemTime(&CurrentTime);
1010         Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1011 
1012         if (Command.Reset != 1)
1013             break;
1014 
1015         if (CurrentTime.QuadPart >= EndTime.QuadPart)
1016         {
1017             if (Command.Reset == 1)
1018             {
1019                 DPRINT1("EHCI_InitializeHardware: Reset failed!\n");
1020                 return MP_STATUS_HW_ERROR;
1021             }
1022 
1023             break;
1024         }
1025     }
1026 
1027     DPRINT("EHCI_InitializeHardware: Reset - OK\n");
1028 
1029     StructuralParams.AsULONG = READ_REGISTER_ULONG(&CapabilityRegisters->StructParameters.AsULONG);
1030 
1031     EhciExtension->NumberOfPorts = StructuralParams.PortCount;
1032     EhciExtension->PortPowerControl = StructuralParams.PortPowerControl;
1033 
1034     DPRINT("EHCI_InitializeHardware: StructuralParams - %X\n", StructuralParams.AsULONG);
1035     DPRINT("EHCI_InitializeHardware: PortPowerControl - %x\n", EhciExtension->PortPowerControl);
1036     DPRINT("EHCI_InitializeHardware: N_PORTS          - %x\n", EhciExtension->NumberOfPorts);
1037 
1038     WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase, 0);
1039     WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase, 0);
1040 
1041     EhciExtension->InterruptMask.AsULONG = 0;
1042     EhciExtension->InterruptMask.Interrupt = 1;
1043     EhciExtension->InterruptMask.ErrorInterrupt = 1;
1044     EhciExtension->InterruptMask.PortChangeInterrupt = 0;
1045     EhciExtension->InterruptMask.FrameListRollover = 1;
1046     EhciExtension->InterruptMask.HostSystemError = 1;
1047     EhciExtension->InterruptMask.InterruptOnAsyncAdvance = 1;
1048 
1049     return MP_STATUS_SUCCESS;
1050 }
1051 
1052 UCHAR
1053 NTAPI
1054 EHCI_GetOffsetEECP(IN PEHCI_EXTENSION EhciExtension,
1055                    IN UCHAR CapabilityID)
1056 {
1057     EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability;
1058     EHCI_HC_CAPABILITY_PARAMS CapParameters;
1059     UCHAR OffsetEECP;
1060 
1061     DPRINT("EHCI_GetOffsetEECP: CapabilityID - %x\n", CapabilityID);
1062 
1063     CapParameters = EhciExtension->CapabilityRegisters->CapParameters;
1064 
1065     OffsetEECP = CapParameters.ExtCapabilitiesPointer;
1066 
1067     if (!OffsetEECP)
1068         return 0;
1069 
1070     while (TRUE)
1071     {
1072         RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1073                                               TRUE,
1074                                               &LegacyCapability.AsULONG,
1075                                               OffsetEECP,
1076                                               sizeof(LegacyCapability));
1077 
1078         DPRINT("EHCI_GetOffsetEECP: OffsetEECP - %x\n", OffsetEECP);
1079 
1080         if (LegacyCapability.CapabilityID == CapabilityID)
1081             break;
1082 
1083         OffsetEECP = LegacyCapability.NextCapabilityPointer;
1084 
1085         if (!OffsetEECP)
1086             return 0;
1087     }
1088 
1089     return OffsetEECP;
1090 }
1091 
1092 MPSTATUS
1093 NTAPI
1094 EHCI_TakeControlHC(IN PEHCI_EXTENSION EhciExtension)
1095 {
1096     LARGE_INTEGER EndTime;
1097     LARGE_INTEGER CurrentTime;
1098     EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability;
1099     UCHAR OffsetEECP;
1100 
1101     DPRINT("EHCI_TakeControlHC: EhciExtension - %p\n", EhciExtension);
1102 
1103     OffsetEECP = EHCI_GetOffsetEECP(EhciExtension, 1);
1104 
1105     if (OffsetEECP == 0)
1106         return MP_STATUS_SUCCESS;
1107 
1108     DPRINT("EHCI_TakeControlHC: OffsetEECP - %X\n", OffsetEECP);
1109 
1110     RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1111                                           TRUE,
1112                                           &LegacyCapability.AsULONG,
1113                                           OffsetEECP,
1114                                           sizeof(LegacyCapability));
1115 
1116     if (LegacyCapability.BiosOwnedSemaphore == 0)
1117         return MP_STATUS_SUCCESS;
1118 
1119     LegacyCapability.OsOwnedSemaphore = 1;
1120 
1121     RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1122                                           FALSE,
1123                                           &LegacyCapability.AsULONG,
1124                                           OffsetEECP,
1125                                           sizeof(LegacyCapability));
1126 
1127     KeQuerySystemTime(&EndTime);
1128     EndTime.QuadPart += 100 * 10000;
1129 
1130     do
1131     {
1132         RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1133                                               TRUE,
1134                                               &LegacyCapability.AsULONG,
1135                                               OffsetEECP,
1136                                               sizeof(LegacyCapability));
1137         KeQuerySystemTime(&CurrentTime);
1138 
1139         if (LegacyCapability.BiosOwnedSemaphore)
1140         {
1141             DPRINT("EHCI_TakeControlHC: Ownership is ok\n");
1142             break;
1143         }
1144     }
1145     while (CurrentTime.QuadPart <= EndTime.QuadPart);
1146 
1147     return MP_STATUS_SUCCESS;
1148 }
1149 
1150 VOID
1151 NTAPI
1152 EHCI_GetRegistryParameters(IN PEHCI_EXTENSION EhciExtension)
1153 {
1154     DPRINT1("EHCI_GetRegistryParameters: UNIMPLEMENTED. FIXME\n");
1155 }
1156 
1157 MPSTATUS
1158 NTAPI
1159 EHCI_StartController(IN PVOID ehciExtension,
1160                      IN PUSBPORT_RESOURCES Resources)
1161 {
1162     PEHCI_EXTENSION EhciExtension = ehciExtension;
1163     PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters;
1164     PEHCI_HW_REGISTERS OperationalRegs;
1165     MPSTATUS MPStatus;
1166     EHCI_USB_COMMAND Command;
1167     UCHAR CapabilityRegLength;
1168     UCHAR Fladj;
1169 
1170     DPRINT("EHCI_StartController: ... \n");
1171 
1172     if ((Resources->ResourcesTypes & (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT)) !=
1173                                      (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT))
1174     {
1175         DPRINT1("EHCI_StartController: Resources->ResourcesTypes - %x\n",
1176                 Resources->ResourcesTypes);
1177 
1178         return MP_STATUS_ERROR;
1179     }
1180 
1181     CapabilityRegisters = (PEHCI_HC_CAPABILITY_REGISTERS)Resources->ResourceBase;
1182     EhciExtension->CapabilityRegisters = CapabilityRegisters;
1183 
1184     CapabilityRegLength = READ_REGISTER_UCHAR(&CapabilityRegisters->RegistersLength);
1185 
1186     OperationalRegs = (PEHCI_HW_REGISTERS)((ULONG_PTR)CapabilityRegisters +
1187                                                       CapabilityRegLength);
1188 
1189     EhciExtension->OperationalRegs = OperationalRegs;
1190 
1191     DPRINT("EHCI_StartController: CapabilityRegisters - %p\n", CapabilityRegisters);
1192     DPRINT("EHCI_StartController: OperationalRegs     - %p\n", OperationalRegs);
1193 
1194     RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1195                                           TRUE,
1196                                           &Fladj,
1197                                           EHCI_FLADJ_PCI_CONFIG_OFFSET,
1198                                           sizeof(Fladj));
1199 
1200     EhciExtension->FrameLengthAdjustment = Fladj;
1201 
1202     EHCI_GetRegistryParameters(EhciExtension);
1203 
1204     MPStatus = EHCI_TakeControlHC(EhciExtension);
1205 
1206     if (MPStatus)
1207     {
1208         DPRINT1("EHCI_StartController: Unsuccessful TakeControlHC()\n");
1209         return MPStatus;
1210     }
1211 
1212     MPStatus = EHCI_InitializeHardware(EhciExtension);
1213 
1214     if (MPStatus)
1215     {
1216         DPRINT1("EHCI_StartController: Unsuccessful InitializeHardware()\n");
1217         return MPStatus;
1218     }
1219 
1220     MPStatus = EHCI_InitializeSchedule(EhciExtension,
1221                                        Resources->StartVA,
1222                                        Resources->StartPA);
1223 
1224     if (MPStatus)
1225     {
1226         DPRINT1("EHCI_StartController: Unsuccessful InitializeSchedule()\n");
1227         return MPStatus;
1228     }
1229 
1230     RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1231                                           TRUE,
1232                                           &Fladj,
1233                                           EHCI_FLADJ_PCI_CONFIG_OFFSET,
1234                                           sizeof(Fladj));
1235 
1236     if (Fladj != EhciExtension->FrameLengthAdjustment)
1237     {
1238         Fladj = EhciExtension->FrameLengthAdjustment;
1239 
1240         RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1241                                               FALSE, // write
1242                                               &Fladj,
1243                                               EHCI_FLADJ_PCI_CONFIG_OFFSET,
1244                                               sizeof(Fladj));
1245     }
1246 
1247     /* Port routing control logic default-routes all ports to this HC */
1248     EhciExtension->PortRoutingControl = EHCI_CONFIG_FLAG_CONFIGURED;
1249     WRITE_REGISTER_ULONG(&OperationalRegs->ConfigFlag,
1250                          EhciExtension->PortRoutingControl);
1251 
1252     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1253     Command.InterruptThreshold = 1; // one micro-frame
1254     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1255 
1256     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1257     Command.Run = 1; // execution of the schedule
1258     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1259 
1260     EhciExtension->IsStarted = TRUE;
1261 
1262     if (Resources->IsChirpHandled)
1263     {
1264         ULONG Port;
1265 
1266         for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++)
1267         {
1268             EHCI_RH_SetFeaturePortPower(EhciExtension, Port);
1269         }
1270 
1271         RegPacket.UsbPortWait(EhciExtension, 200);
1272 
1273         for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++)
1274         {
1275             EHCI_RH_ChirpRootPort(EhciExtension, Port++);
1276         }
1277     }
1278 
1279     return MPStatus;
1280 }
1281 
1282 VOID
1283 NTAPI
1284 EHCI_StopController(IN PVOID ehciExtension,
1285                     IN BOOLEAN DisableInterrupts)
1286 {
1287     DPRINT1("EHCI_StopController: UNIMPLEMENTED. FIXME\n");
1288 }
1289 
1290 VOID
1291 NTAPI
1292 EHCI_SuspendController(IN PVOID ehciExtension)
1293 {
1294     PEHCI_EXTENSION EhciExtension = ehciExtension;
1295     PEHCI_HW_REGISTERS OperationalRegs;
1296     EHCI_USB_COMMAND Command;
1297     EHCI_USB_STATUS Status;
1298     EHCI_INTERRUPT_ENABLE IntrEn;
1299     ULONG ix;
1300 
1301     DPRINT("EHCI_SuspendController: ... \n");
1302 
1303     OperationalRegs = EhciExtension->OperationalRegs;
1304 
1305     EhciExtension->BackupPeriodiclistbase = READ_REGISTER_ULONG(&OperationalRegs->PeriodicListBase);
1306     EhciExtension->BackupAsynclistaddr = READ_REGISTER_ULONG(&OperationalRegs->AsyncListBase);
1307     EhciExtension->BackupCtrlDSSegment = READ_REGISTER_ULONG(&OperationalRegs->SegmentSelector);
1308     EhciExtension->BackupUSBCmd = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1309 
1310     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1311     Command.InterruptAdvanceDoorbell = 0;
1312     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1313 
1314     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1315     Command.Run = 0;
1316     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1317 
1318     KeStallExecutionProcessor(125);
1319 
1320     Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1321 
1322     Status.HCHalted = 0;
1323     Status.Reclamation = 0;
1324     Status.PeriodicStatus = 0;
1325     Status.AsynchronousStatus = 0;
1326 
1327     if (Status.AsULONG)
1328         WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, Status.AsULONG);
1329 
1330     WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, 0);
1331 
1332     for (ix = 0; ix < 10; ix++)
1333     {
1334         Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1335 
1336         if (Status.HCHalted)
1337             break;
1338 
1339         RegPacket.UsbPortWait(EhciExtension, 1);
1340     }
1341 
1342     if (!Status.HCHalted)
1343         DbgBreakPoint();
1344 
1345     IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG);
1346     IntrEn.PortChangeInterrupt = 1;
1347     WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, IntrEn.AsULONG);
1348 
1349     EhciExtension->Flags |= EHCI_FLAGS_CONTROLLER_SUSPEND;
1350 }
1351 
1352 MPSTATUS
1353 NTAPI
1354 EHCI_ResumeController(IN PVOID ehciExtension)
1355 {
1356     PEHCI_EXTENSION EhciExtension = ehciExtension;
1357     PEHCI_HW_REGISTERS OperationalRegs;
1358     ULONG RoutingControl;
1359     EHCI_USB_COMMAND Command;
1360 
1361     DPRINT("EHCI_ResumeController: ... \n");
1362 
1363     OperationalRegs = EhciExtension->OperationalRegs;
1364 
1365     RoutingControl = EhciExtension->PortRoutingControl;
1366 
1367     if (!(RoutingControl & EHCI_CONFIG_FLAG_CONFIGURED))
1368     {
1369         EhciExtension->PortRoutingControl = RoutingControl | EHCI_CONFIG_FLAG_CONFIGURED;
1370         WRITE_REGISTER_ULONG(&OperationalRegs->ConfigFlag,
1371                              EhciExtension->PortRoutingControl);
1372 
1373         return MP_STATUS_HW_ERROR;
1374     }
1375 
1376     WRITE_REGISTER_ULONG(&OperationalRegs->SegmentSelector,
1377                          EhciExtension->BackupCtrlDSSegment);
1378 
1379     WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase,
1380                          EhciExtension->BackupPeriodiclistbase);
1381 
1382     WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase,
1383                          EhciExtension->BackupAsynclistaddr);
1384 
1385     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1386 
1387     Command.AsULONG = Command.AsULONG ^ EhciExtension->BackupUSBCmd;
1388 
1389     Command.Reset = 0;
1390     Command.FrameListSize = 0;
1391     Command.InterruptAdvanceDoorbell = 0;
1392     Command.LightResetHC = 0;
1393     Command.AsynchronousParkModeCount = 0;
1394     Command.AsynchronousParkModeEnable = 0;
1395 
1396     Command.Run = 1;
1397 
1398     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG,
1399                          Command.AsULONG);
1400 
1401     WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG,
1402                          EhciExtension->InterruptMask.AsULONG);
1403 
1404     EhciExtension->Flags &= ~EHCI_FLAGS_CONTROLLER_SUSPEND;
1405 
1406     return MP_STATUS_SUCCESS;
1407 }
1408 
1409 BOOLEAN
1410 NTAPI
1411 EHCI_HardwarePresent(IN PEHCI_EXTENSION EhciExtension,
1412                      IN BOOLEAN IsInvalidateController)
1413 {
1414     PEHCI_HW_REGISTERS OperationalRegs = EhciExtension->OperationalRegs;
1415 
1416     if (READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG) != -1)
1417         return TRUE;
1418 
1419     DPRINT1("EHCI_HardwarePresent: IsInvalidateController - %x\n",
1420             IsInvalidateController);
1421 
1422     if (!IsInvalidateController)
1423         return FALSE;
1424 
1425     RegPacket.UsbPortInvalidateController(EhciExtension,
1426                                           USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE);
1427     return FALSE;
1428 }
1429 
1430 BOOLEAN
1431 NTAPI
1432 EHCI_InterruptService(IN PVOID ehciExtension)
1433 {
1434     PEHCI_EXTENSION EhciExtension = ehciExtension;
1435     PEHCI_HW_REGISTERS OperationalRegs;
1436     BOOLEAN Result = FALSE;
1437     EHCI_USB_STATUS IntrSts;
1438     EHCI_INTERRUPT_ENABLE IntrEn;
1439     EHCI_INTERRUPT_ENABLE iStatus;
1440     EHCI_USB_COMMAND Command;
1441     ULONG FrameIndex;
1442 
1443     OperationalRegs = EhciExtension->OperationalRegs;
1444 
1445     DPRINT_EHCI("EHCI_InterruptService: ... \n");
1446 
1447     Result = EHCI_HardwarePresent(EhciExtension, FALSE);
1448 
1449     if (!Result)
1450         return FALSE;
1451 
1452     IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG);
1453     IntrSts.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1454 
1455     iStatus.AsULONG = (IntrEn.AsULONG & IntrSts.AsULONG) & EHCI_INTERRUPT_MASK;
1456 
1457     if (!iStatus.AsULONG)
1458         return FALSE;
1459 
1460     EhciExtension->InterruptStatus = iStatus;
1461 
1462     WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, iStatus.AsULONG);
1463 
1464     if (iStatus.HostSystemError)
1465     {
1466         EhciExtension->HcSystemErrors++;
1467 
1468         if (EhciExtension->HcSystemErrors < EHCI_MAX_HC_SYSTEM_ERRORS)
1469         {
1470             Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1471             Command.Run = 1;
1472             WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1473         }
1474     }
1475 
1476     FrameIndex = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) / EHCI_MICROFRAMES;
1477     FrameIndex &= EHCI_FRINDEX_FRAME_MASK;
1478 
1479     if ((FrameIndex ^ EhciExtension->FrameIndex) & EHCI_FRAME_LIST_MAX_ENTRIES)
1480     {
1481         EhciExtension->FrameHighPart += 2 * EHCI_FRAME_LIST_MAX_ENTRIES;
1482 
1483         EhciExtension->FrameHighPart -= (FrameIndex ^ EhciExtension->FrameHighPart) &
1484                                         EHCI_FRAME_LIST_MAX_ENTRIES;
1485     }
1486 
1487     EhciExtension->FrameIndex = FrameIndex;
1488 
1489     return TRUE;
1490 }
1491 
1492 VOID
1493 NTAPI
1494 EHCI_InterruptDpc(IN PVOID ehciExtension,
1495                   IN BOOLEAN EnableInterrupts)
1496 {
1497     PEHCI_EXTENSION EhciExtension = ehciExtension;
1498     PEHCI_HW_REGISTERS OperationalRegs;
1499     EHCI_INTERRUPT_ENABLE iStatus;
1500 
1501     OperationalRegs = EhciExtension->OperationalRegs;
1502 
1503     DPRINT_EHCI("EHCI_InterruptDpc: [%p] EnableInterrupts - %x\n",
1504                 EhciExtension, EnableInterrupts);
1505 
1506     iStatus = EhciExtension->InterruptStatus;
1507     EhciExtension->InterruptStatus.AsULONG = 0;
1508 
1509     if (iStatus.Interrupt == 1 ||
1510         iStatus.ErrorInterrupt == 1 ||
1511         iStatus.InterruptOnAsyncAdvance == 1)
1512     {
1513         DPRINT_EHCI("EHCI_InterruptDpc: [%p] InterruptStatus - %X\n", EhciExtension, iStatus.AsULONG);
1514         RegPacket.UsbPortInvalidateEndpoint(EhciExtension, NULL);
1515     }
1516 
1517     if (iStatus.PortChangeInterrupt == 1)
1518     {
1519         DPRINT_EHCI("EHCI_InterruptDpc: [%p] PortChangeInterrupt\n", EhciExtension);
1520         RegPacket.UsbPortInvalidateRootHub(EhciExtension);
1521     }
1522 
1523     if (EnableInterrupts)
1524     {
1525         WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG,
1526                              EhciExtension->InterruptMask.AsULONG);
1527     }
1528 }
1529 
1530 ULONG
1531 NTAPI
1532 EHCI_MapAsyncTransferToTd(IN PEHCI_EXTENSION EhciExtension,
1533                           IN ULONG MaxPacketSize,
1534                           IN ULONG TransferedLen,
1535                           IN PULONG DataToggle,
1536                           IN PEHCI_TRANSFER EhciTransfer,
1537                           IN PEHCI_HCD_TD TD,
1538                           IN PUSBPORT_SCATTER_GATHER_LIST SgList)
1539 {
1540     PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1541     PUSBPORT_SCATTER_GATHER_ELEMENT SgElement;
1542     ULONG SgIdx;
1543     ULONG LengthThisTD;
1544     ULONG ix;
1545     ULONG SgRemain;
1546     ULONG DiffLength;
1547     ULONG NumPackets;
1548 
1549     DPRINT_EHCI("EHCI_MapAsyncTransferToTd: EhciTransfer - %p, TD - %p, TransferedLen - %x, MaxPacketSize - %x, DataToggle - %x\n",
1550                 EhciTransfer,
1551                 TD,
1552                 TransferedLen,
1553                 MaxPacketSize,
1554                 DataToggle);
1555 
1556     TransferParameters = EhciTransfer->TransferParameters;
1557 
1558     SgElement = &SgList->SgElement[0];
1559 
1560     for (SgIdx = 0; SgIdx < SgList->SgElementCount; SgIdx++)
1561     {
1562         if (TransferedLen >= SgElement->SgOffset &&
1563             TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength)
1564         {
1565             break;
1566         }
1567 
1568         SgElement += 1;
1569     }
1570 
1571     SgRemain = SgList->SgElementCount - SgIdx;
1572 
1573     if (SgRemain > EHCI_MAX_QTD_BUFFER_PAGES)
1574     {
1575         TD->HwTD.Buffer[0] = SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart -
1576                              SgList->SgElement[SgIdx].SgOffset +
1577                              TransferedLen;
1578 
1579         LengthThisTD = EHCI_MAX_QTD_BUFFER_PAGES * PAGE_SIZE -
1580                        (TD->HwTD.Buffer[0] & (PAGE_SIZE - 1));
1581 
1582         for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; ix++)
1583         {
1584             TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart;
1585         }
1586 
1587         NumPackets = LengthThisTD / MaxPacketSize;
1588         DiffLength = LengthThisTD - MaxPacketSize * (LengthThisTD / MaxPacketSize);
1589 
1590         if (LengthThisTD != MaxPacketSize * (LengthThisTD / MaxPacketSize))
1591             LengthThisTD -= DiffLength;
1592 
1593         if (DataToggle && (NumPackets & 1))
1594             *DataToggle = !(*DataToggle);
1595     }
1596     else
1597     {
1598         LengthThisTD = TransferParameters->TransferBufferLength - TransferedLen;
1599 
1600         TD->HwTD.Buffer[0] = TransferedLen +
1601                              SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart -
1602                              SgList->SgElement[SgIdx].SgOffset;
1603 
1604         for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; ix++)
1605         {
1606             if ((SgIdx + ix) >= SgList->SgElementCount)
1607                 break;
1608 
1609             TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart;
1610         }
1611     }
1612 
1613     TD->HwTD.Token.TransferBytes = LengthThisTD;
1614     TD->LengthThisTD = LengthThisTD;
1615 
1616     return LengthThisTD + TransferedLen;
1617 }
1618 
1619 VOID
1620 NTAPI
1621 EHCI_EnableAsyncList(IN PEHCI_EXTENSION EhciExtension)
1622 {
1623     PEHCI_HW_REGISTERS OperationalRegs;
1624     EHCI_USB_COMMAND UsbCmd;
1625 
1626     DPRINT_EHCI("EHCI_EnableAsyncList: ... \n");
1627 
1628     OperationalRegs = EhciExtension->OperationalRegs;
1629 
1630     UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1631     UsbCmd.AsynchronousEnable = 1;
1632     WRITE_REGISTER_ULONG((&OperationalRegs->HcCommand.AsULONG), UsbCmd.AsULONG);
1633 }
1634 
1635 VOID
1636 NTAPI
1637 EHCI_DisableAsyncList(IN PEHCI_EXTENSION EhciExtension)
1638 {
1639     PEHCI_HW_REGISTERS OperationalRegs;
1640     EHCI_USB_COMMAND UsbCmd;
1641 
1642     DPRINT("EHCI_DisableAsyncList: ... \n");
1643 
1644     OperationalRegs = EhciExtension->OperationalRegs;
1645 
1646     UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1647     UsbCmd.AsynchronousEnable = 0;
1648     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, UsbCmd.AsULONG);
1649 }
1650 
1651 VOID
1652 NTAPI
1653 EHCI_EnablePeriodicList(IN PEHCI_EXTENSION EhciExtension)
1654 {
1655     PEHCI_HW_REGISTERS OperationalRegs;
1656     EHCI_USB_COMMAND Command;
1657 
1658     DPRINT("EHCI_EnablePeriodicList: ... \n");
1659 
1660     OperationalRegs = EhciExtension->OperationalRegs;
1661 
1662     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1663     Command.PeriodicEnable = 1;
1664     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1665 }
1666 
1667 VOID
1668 NTAPI
1669 EHCI_FlushAsyncCache(IN PEHCI_EXTENSION EhciExtension)
1670 {
1671     PEHCI_HW_REGISTERS OperationalRegs;
1672     EHCI_USB_COMMAND Command;
1673     EHCI_USB_STATUS Status;
1674     LARGE_INTEGER CurrentTime;
1675     LARGE_INTEGER EndTime;
1676     EHCI_USB_COMMAND Cmd;
1677 
1678     DPRINT_EHCI("EHCI_FlushAsyncCache: EhciExtension - %p\n", EhciExtension);
1679 
1680     OperationalRegs = EhciExtension->OperationalRegs;
1681     Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1682     Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1683 
1684     if (!Status.AsynchronousStatus && !Command.AsynchronousEnable)
1685         return;
1686 
1687     if (Status.AsynchronousStatus && !Command.AsynchronousEnable)
1688     {
1689         KeQuerySystemTime(&EndTime);
1690         EndTime.QuadPart += 100 * 10000;  //100 ms
1691 
1692         do
1693         {
1694             Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1695             Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1696             KeQuerySystemTime(&CurrentTime);
1697 
1698             if (CurrentTime.QuadPart > EndTime.QuadPart)
1699                 RegPacket.UsbPortBugCheck(EhciExtension);
1700         }
1701         while (Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run);
1702 
1703         return;
1704     }
1705 
1706     if (!Status.AsynchronousStatus && Command.AsynchronousEnable)
1707     {
1708         KeQuerySystemTime(&EndTime);
1709         EndTime.QuadPart += 100 * 10000;  //100 ms
1710 
1711         do
1712         {
1713             Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1714             Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1715             KeQuerySystemTime(&CurrentTime);
1716         }
1717         while (!Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run);
1718     }
1719 
1720     Command.InterruptAdvanceDoorbell = 1;
1721     WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1722 
1723     KeQuerySystemTime(&EndTime);
1724     EndTime.QuadPart += 100 * 10000;  //100 ms
1725 
1726     Cmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1727 
1728     if (Cmd.InterruptAdvanceDoorbell)
1729     {
1730         while (Cmd.Run)
1731         {
1732             if (Cmd.AsULONG == -1)
1733                 break;
1734 
1735             KeStallExecutionProcessor(1);
1736             Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1737             KeQuerySystemTime(&CurrentTime);
1738 
1739             if (!Command.InterruptAdvanceDoorbell)
1740                 break;
1741 
1742             Cmd = Command;
1743         }
1744     }
1745 
1746     /* InterruptOnAsyncAdvance */
1747     WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, 0x20);
1748 }
1749 
1750 VOID
1751 NTAPI
1752 EHCI_LockQH(IN PEHCI_EXTENSION EhciExtension,
1753             IN PEHCI_HCD_QH QH,
1754             IN ULONG TransferType)
1755 {
1756     PEHCI_HCD_QH PrevQH;
1757     PEHCI_HCD_QH NextQH;
1758     ULONG QhPA;
1759     ULONG FrameIndexReg;
1760     PEHCI_HW_REGISTERS OperationalRegs;
1761     EHCI_USB_COMMAND Command;
1762 
1763     DPRINT_EHCI("EHCI_LockQH: QH - %p, TransferType - %x\n",
1764                 QH,
1765                 TransferType);
1766 
1767     OperationalRegs = EhciExtension->OperationalRegs;
1768 
1769     ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING) == 0);
1770     ASSERT(EhciExtension->LockQH == NULL);
1771 
1772     PrevQH = QH->sqh.PrevHead;
1773     QH->sqh.QhFlags |= EHCI_QH_FLAG_UPDATING;
1774 
1775     ASSERT(PrevQH);
1776 
1777     NextQH = QH->sqh.NextHead;
1778 
1779     EhciExtension->PrevQH = PrevQH;
1780     EhciExtension->NextQH = NextQH;
1781     EhciExtension->LockQH = QH;
1782 
1783     if (NextQH)
1784     {
1785         QhPA = NextQH->sqh.PhysicalAddress;
1786         QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
1787         QhPA |= (EHCI_LINK_TYPE_QH << 1);
1788     }
1789     else
1790     {
1791         QhPA = TERMINATE_POINTER;
1792     }
1793 
1794     PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
1795 
1796     FrameIndexReg = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex);
1797 
1798     if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1799     {
1800         do
1801         {
1802             Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1803         }
1804         while (READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) ==
1805                FrameIndexReg && (Command.AsULONG != -1) && Command.Run);
1806     }
1807     else
1808     {
1809         EHCI_FlushAsyncCache(EhciExtension);
1810     }
1811 }
1812 
1813 VOID
1814 NTAPI
1815 EHCI_UnlockQH(IN PEHCI_EXTENSION EhciExtension,
1816               IN PEHCI_HCD_QH QH)
1817 {
1818     ULONG QhPA;
1819 
1820     DPRINT_EHCI("EHCI_UnlockQH: QH - %p\n", QH);
1821 
1822     ASSERT(QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING);
1823     ASSERT(EhciExtension->LockQH);
1824     ASSERT(EhciExtension->LockQH == QH);
1825 
1826     QH->sqh.QhFlags &= ~EHCI_QH_FLAG_UPDATING;
1827 
1828     EhciExtension->LockQH = NULL;
1829 
1830     QhPA = QH->sqh.PhysicalAddress;
1831     QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
1832     QhPA |= (EHCI_LINK_TYPE_QH << 1);
1833 
1834     EhciExtension->PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
1835 }
1836 
1837 VOID
1838 NTAPI
1839 EHCI_LinkTransferToQueue(IN PEHCI_EXTENSION EhciExtension,
1840                          IN PEHCI_ENDPOINT EhciEndpoint,
1841                          IN PEHCI_HCD_TD NextTD)
1842 {
1843     PEHCI_HCD_QH QH;
1844     PEHCI_HCD_TD TD;
1845     PEHCI_TRANSFER Transfer;
1846     PEHCI_HCD_TD LinkTD;
1847     BOOLEAN IsPresent;
1848     ULONG ix;
1849 
1850     DPRINT_EHCI("EHCI_LinkTransferToQueue: EhciEndpoint - %p, NextTD - %p\n",
1851                 EhciEndpoint,
1852                 NextTD);
1853 
1854     ASSERT(EhciEndpoint->HcdHeadP != NULL);
1855     IsPresent = EHCI_HardwarePresent(EhciExtension, 0);
1856 
1857     QH = EhciEndpoint->QH;
1858     TD = EhciEndpoint->HcdHeadP;
1859 
1860     if (TD == EhciEndpoint->HcdTailP)
1861     {
1862         if (IsPresent)
1863         {
1864             EHCI_LockQH(EhciExtension,
1865                         QH,
1866                         EhciEndpoint->EndpointProperties.TransferType);
1867         }
1868 
1869         QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
1870         QH->sqh.HwQH.NextTD = NextTD->PhysicalAddress;
1871         QH->sqh.HwQH.AlternateNextTD = NextTD->HwTD.AlternateNextTD;
1872 
1873         QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
1874                                              EHCI_TOKEN_STATUS_HALTED);
1875 
1876         QH->sqh.HwQH.Token.TransferBytes = 0;
1877 
1878         if (IsPresent)
1879             EHCI_UnlockQH(EhciExtension, QH);
1880 
1881         EhciEndpoint->HcdHeadP = NextTD;
1882     }
1883     else
1884     {
1885         DPRINT_EHCI("EHCI_LinkTransferToQueue: TD - %p, HcdTailP - %p\n",
1886                     EhciEndpoint->HcdHeadP,
1887                     EhciEndpoint->HcdTailP);
1888 
1889         LinkTD = EhciEndpoint->HcdHeadP;
1890 
1891         while (TD != EhciEndpoint->HcdTailP)
1892         {
1893             LinkTD = TD;
1894             TD = TD->NextHcdTD;
1895         }
1896 
1897         ASSERT(LinkTD != EhciEndpoint->HcdTailP);
1898 
1899         Transfer = LinkTD->EhciTransfer;
1900 
1901         TD = EhciEndpoint->FirstTD;
1902 
1903         for (ix = 0; ix < EhciEndpoint->MaxTDs; ix++)
1904         {
1905             if (TD->EhciTransfer == Transfer)
1906             {
1907                 TD->AltNextHcdTD = NextTD;
1908                 TD->HwTD.AlternateNextTD = NextTD->PhysicalAddress;
1909             }
1910 
1911             TD += 1;
1912         }
1913 
1914         LinkTD->HwTD.NextTD = NextTD->PhysicalAddress;
1915         LinkTD->NextHcdTD = NextTD;
1916 
1917         if (QH->sqh.HwQH.CurrentTD == LinkTD->PhysicalAddress)
1918         {
1919             QH->sqh.HwQH.NextTD = NextTD->PhysicalAddress;
1920             QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
1921         }
1922     }
1923 }
1924 
1925 MPSTATUS
1926 NTAPI
1927 EHCI_ControlTransfer(IN PEHCI_EXTENSION EhciExtension,
1928                      IN PEHCI_ENDPOINT EhciEndpoint,
1929                      IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1930                      IN PEHCI_TRANSFER EhciTransfer,
1931                      IN PUSBPORT_SCATTER_GATHER_LIST SgList)
1932 {
1933     PEHCI_HCD_TD FirstTD;
1934     PEHCI_HCD_TD LastTD;
1935     PEHCI_HCD_TD TD;
1936     PEHCI_HCD_TD PrevTD;
1937     PEHCI_HCD_TD LinkTD;
1938     ULONG TransferedLen = 0;
1939     EHCI_TD_TOKEN Token;
1940     ULONG DataToggle = 1;
1941 
1942     DPRINT_EHCI("EHCI_ControlTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
1943                 EhciEndpoint,
1944                 EhciTransfer);
1945 
1946     if (EhciEndpoint->RemainTDs < EHCI_MAX_CONTROL_TD_COUNT)
1947         return MP_STATUS_FAILURE;
1948 
1949     EhciExtension->PendingTransfers++;
1950     EhciEndpoint->PendingTDs++;
1951 
1952     EhciTransfer->TransferOnAsyncList = 1;
1953 
1954     FirstTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
1955 
1956     if (!FirstTD)
1957     {
1958         RegPacket.UsbPortBugCheck(EhciExtension);
1959         return MP_STATUS_FAILURE;
1960     }
1961 
1962     EhciTransfer->PendingTDs++;
1963 
1964     FirstTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
1965     FirstTD->EhciTransfer = EhciTransfer;
1966 
1967     FirstTD->HwTD.Buffer[0] = FirstTD->PhysicalAddress + FIELD_OFFSET(EHCI_HCD_TD, SetupPacket);
1968     FirstTD->HwTD.Buffer[1] = 0;
1969     FirstTD->HwTD.Buffer[2] = 0;
1970     FirstTD->HwTD.Buffer[3] = 0;
1971     FirstTD->HwTD.Buffer[4] = 0;
1972 
1973     FirstTD->NextHcdTD = NULL;
1974 
1975     FirstTD->HwTD.NextTD = TERMINATE_POINTER;
1976     FirstTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
1977 
1978     FirstTD->HwTD.Token.AsULONG = 0;
1979     FirstTD->HwTD.Token.ErrorCounter = 3;
1980     FirstTD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_SETUP;
1981     FirstTD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
1982     FirstTD->HwTD.Token.TransferBytes = sizeof(FirstTD->SetupPacket);
1983 
1984     RtlCopyMemory(&FirstTD->SetupPacket,
1985                   &TransferParameters->SetupPacket,
1986                   sizeof(FirstTD->SetupPacket));
1987 
1988     LastTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
1989 
1990     if (!LastTD)
1991     {
1992         RegPacket.UsbPortBugCheck(EhciExtension);
1993         return MP_STATUS_FAILURE;
1994     }
1995 
1996     EhciTransfer->PendingTDs++;
1997 
1998     LastTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
1999     LastTD->EhciTransfer = EhciTransfer;
2000 
2001     LastTD->HwTD.Buffer[0] = 0;
2002     LastTD->HwTD.Buffer[1] = 0;
2003     LastTD->HwTD.Buffer[2] = 0;
2004     LastTD->HwTD.Buffer[3] = 0;
2005     LastTD->HwTD.Buffer[4] = 0;
2006 
2007     LastTD->NextHcdTD = NULL;
2008     LastTD->HwTD.NextTD = TERMINATE_POINTER;
2009     LastTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2010 
2011     LastTD->HwTD.Token.AsULONG = 0;
2012     LastTD->HwTD.Token.ErrorCounter = 3;
2013 
2014     FirstTD->AltNextHcdTD = LastTD;
2015     FirstTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2016 
2017     PrevTD = FirstTD;
2018     LinkTD = FirstTD;
2019 
2020     while (TransferedLen < TransferParameters->TransferBufferLength)
2021     {
2022         TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2023 
2024         if (!TD)
2025         {
2026             RegPacket.UsbPortBugCheck(EhciExtension);
2027             return MP_STATUS_FAILURE;
2028         }
2029 
2030         LinkTD = TD;
2031 
2032         EhciTransfer->PendingTDs++;
2033 
2034         TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2035         TD->EhciTransfer = EhciTransfer;
2036 
2037         TD->HwTD.Buffer[0] = 0;
2038         TD->HwTD.Buffer[1] = 0;
2039         TD->HwTD.Buffer[2] = 0;
2040         TD->HwTD.Buffer[3] = 0;
2041         TD->HwTD.Buffer[4] = 0;
2042 
2043         TD->NextHcdTD = NULL;
2044 
2045         TD->HwTD.NextTD = TERMINATE_POINTER;
2046         TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2047 
2048         TD->HwTD.Token.AsULONG = 0;
2049         TD->HwTD.Token.ErrorCounter = 3;
2050 
2051         PrevTD->NextHcdTD = TD;
2052         PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2053 
2054         if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2055             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2056         else
2057             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2058 
2059         TD->HwTD.Token.DataToggle = DataToggle;
2060         TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2061 
2062         if (DataToggle)
2063             TD->HwTD.Token.DataToggle = 1;
2064         else
2065             TD->HwTD.Token.DataToggle = 0;
2066 
2067         TD->AltNextHcdTD = LastTD;
2068         TD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2069 
2070         TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2071                                                   EhciEndpoint->EndpointProperties.MaxPacketSize,
2072                                                   TransferedLen,
2073                                                   &DataToggle,
2074                                                   EhciTransfer,
2075                                                   TD,
2076                                                   SgList);
2077 
2078         PrevTD = TD;
2079     }
2080 
2081     LinkTD->NextHcdTD = LastTD;
2082     LinkTD->HwTD.NextTD = LastTD->PhysicalAddress;
2083 
2084     LastTD->HwTD.Buffer[0] = 0;
2085     LastTD->LengthThisTD = 0;
2086 
2087     Token.AsULONG = 0;
2088     Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2089     Token.InterruptOnComplete = 1;
2090     Token.DataToggle = 1;
2091 
2092     if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2093         Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2094     else
2095         Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2096 
2097     LastTD->HwTD.Token = Token;
2098 
2099     LastTD->NextHcdTD = EhciEndpoint->HcdTailP;
2100     LastTD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2101 
2102     EHCI_EnableAsyncList(EhciExtension);
2103     EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2104 
2105     ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL);
2106     ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL);
2107 
2108     return MP_STATUS_SUCCESS;
2109 }
2110 
2111 MPSTATUS
2112 NTAPI
2113 EHCI_BulkTransfer(IN PEHCI_EXTENSION EhciExtension,
2114                   IN PEHCI_ENDPOINT EhciEndpoint,
2115                   IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2116                   IN PEHCI_TRANSFER EhciTransfer,
2117                   IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2118 {
2119     PEHCI_HCD_TD PrevTD;
2120     PEHCI_HCD_TD FirstTD;
2121     PEHCI_HCD_TD TD;
2122     ULONG TransferedLen;
2123 
2124     DPRINT_EHCI("EHCI_BulkTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2125                 EhciEndpoint,
2126                 EhciTransfer);
2127 
2128     if (((TransferParameters->TransferBufferLength /
2129         ((EHCI_MAX_QTD_BUFFER_PAGES - 1) * PAGE_SIZE)) + 1) > EhciEndpoint->RemainTDs)
2130     {
2131         DPRINT1("EHCI_BulkTransfer: return MP_STATUS_FAILURE\n");
2132         return MP_STATUS_FAILURE;
2133     }
2134 
2135     EhciExtension->PendingTransfers++;
2136     EhciEndpoint->PendingTDs++;
2137 
2138     EhciTransfer->TransferOnAsyncList = 1;
2139 
2140     TransferedLen = 0;
2141     PrevTD = NULL;
2142 
2143     if (TransferParameters->TransferBufferLength)
2144     {
2145         while (TransferedLen < TransferParameters->TransferBufferLength)
2146         {
2147             TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2148 
2149             if (!TD)
2150             {
2151                 RegPacket.UsbPortBugCheck(EhciExtension);
2152                 return MP_STATUS_FAILURE;
2153             }
2154 
2155             EhciTransfer->PendingTDs++;
2156 
2157             TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2158             TD->EhciTransfer = EhciTransfer;
2159 
2160             TD->HwTD.Buffer[0] = 0;
2161             TD->HwTD.Buffer[1] = 0;
2162             TD->HwTD.Buffer[2] = 0;
2163             TD->HwTD.Buffer[3] = 0;
2164             TD->HwTD.Buffer[4] = 0;
2165 
2166             TD->NextHcdTD = NULL;
2167             TD->HwTD.NextTD = TERMINATE_POINTER;
2168             TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2169 
2170             TD->HwTD.Token.AsULONG = 0;
2171             TD->HwTD.Token.ErrorCounter = 3;
2172 
2173             if (EhciTransfer->PendingTDs == 1)
2174             {
2175                 FirstTD = TD;
2176             }
2177             else
2178             {
2179                 PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2180                 PrevTD->NextHcdTD = TD;
2181             }
2182 
2183             TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2184             TD->AltNextHcdTD = EhciEndpoint->HcdTailP;
2185 
2186             TD->HwTD.Token.InterruptOnComplete = 1;
2187 
2188             if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2189                 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2190             else
2191                 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2192 
2193             TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2194             TD->HwTD.Token.DataToggle = 1;
2195 
2196             TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2197                                                       EhciEndpoint->EndpointProperties.MaxPacketSize,
2198                                                       TransferedLen,
2199                                                       0,
2200                                                       EhciTransfer,
2201                                                       TD,
2202                                                       SgList);
2203 
2204             PrevTD = TD;
2205         }
2206     }
2207     else
2208     {
2209         TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2210 
2211         if (!TD)
2212         {
2213             RegPacket.UsbPortBugCheck(EhciExtension);
2214             return MP_STATUS_FAILURE;
2215         }
2216 
2217         EhciTransfer->PendingTDs++;
2218 
2219         TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2220         TD->EhciTransfer = EhciTransfer;
2221 
2222         TD->HwTD.Buffer[0] = 0;
2223         TD->HwTD.Buffer[1] = 0;
2224         TD->HwTD.Buffer[2] = 0;
2225         TD->HwTD.Buffer[3] = 0;
2226         TD->HwTD.Buffer[4] = 0;
2227 
2228         TD->HwTD.NextTD = TERMINATE_POINTER;
2229         TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2230 
2231         TD->HwTD.Token.AsULONG = 0;
2232         TD->HwTD.Token.ErrorCounter = 3;
2233 
2234         TD->NextHcdTD = NULL;
2235 
2236         ASSERT(EhciTransfer->PendingTDs == 1);
2237 
2238         FirstTD = TD;
2239 
2240         TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2241         TD->AltNextHcdTD = EhciEndpoint->HcdTailP;
2242 
2243         TD->HwTD.Token.InterruptOnComplete = 1;
2244 
2245         if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2246             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2247         else
2248             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2249 
2250         TD->HwTD.Buffer[0] = TD->PhysicalAddress;
2251 
2252         TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2253         TD->HwTD.Token.DataToggle = 1;
2254 
2255         TD->LengthThisTD = 0;
2256     }
2257 
2258     TD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2259     TD->NextHcdTD = EhciEndpoint->HcdTailP;
2260 
2261     EHCI_EnableAsyncList(EhciExtension);
2262     EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2263 
2264     ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == 0);
2265     ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == 0);
2266 
2267     return MP_STATUS_SUCCESS;
2268 }
2269 
2270 MPSTATUS
2271 NTAPI
2272 EHCI_InterruptTransfer(IN PEHCI_EXTENSION EhciExtension,
2273                        IN PEHCI_ENDPOINT EhciEndpoint,
2274                        IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2275                        IN PEHCI_TRANSFER EhciTransfer,
2276                        IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2277 {
2278     PEHCI_HCD_TD TD;
2279     PEHCI_HCD_TD FirstTD;
2280     PEHCI_HCD_TD PrevTD = NULL;
2281     ULONG TransferedLen = 0;
2282 
2283     DPRINT_EHCI("EHCI_InterruptTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2284                 EhciEndpoint,
2285                 EhciTransfer);
2286 
2287     if (!EhciEndpoint->RemainTDs)
2288     {
2289         DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2290         DbgBreakPoint();
2291         return MP_STATUS_FAILURE;
2292     }
2293 
2294     EhciEndpoint->PendingTDs++;
2295 
2296     if (!TransferParameters->TransferBufferLength)
2297     {
2298         DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2299         DbgBreakPoint();
2300         return MP_STATUS_FAILURE;
2301     }
2302 
2303     while (TransferedLen < TransferParameters->TransferBufferLength)
2304     {
2305         TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2306 
2307         if (!TD)
2308         {
2309             DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2310             RegPacket.UsbPortBugCheck(EhciExtension);
2311             return MP_STATUS_FAILURE;
2312         }
2313 
2314         EhciTransfer->PendingTDs++;
2315 
2316         TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2317         TD->EhciTransfer = EhciTransfer;
2318 
2319         TD->HwTD.Buffer[0] = 0;
2320         TD->HwTD.Buffer[1] = 0;
2321         TD->HwTD.Buffer[2] = 0;
2322         TD->HwTD.Buffer[3] = 0;
2323         TD->HwTD.Buffer[4] = 0;
2324 
2325         TD->HwTD.NextTD = TERMINATE_POINTER;
2326         TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2327 
2328         TD->HwTD.Token.AsULONG = 0;
2329         TD->HwTD.Token.ErrorCounter = 3;
2330 
2331         TD->NextHcdTD = NULL;
2332 
2333         if (EhciTransfer->PendingTDs == 1)
2334         {
2335             FirstTD = TD;
2336         }
2337         else if (PrevTD)
2338         {
2339             PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2340             PrevTD->NextHcdTD = TD;
2341         }
2342 
2343         if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2344             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2345         else
2346             TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2347 
2348         TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2349         TD->HwTD.Token.DataToggle = 1;
2350 
2351         TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2352                                                   EhciEndpoint->EndpointProperties.TotalMaxPacketSize,
2353                                                   TransferedLen,
2354                                                   NULL,
2355                                                   EhciTransfer,
2356                                                   TD,
2357                                                   SgList);
2358 
2359         PrevTD = TD;
2360     }
2361 
2362     TD->HwTD.Token.InterruptOnComplete = 1;
2363 
2364     DPRINT_EHCI("EHCI_InterruptTransfer: PendingTDs - %x, TD->PhysicalAddress - %p, FirstTD - %p\n",
2365                 EhciTransfer->PendingTDs,
2366                 TD->PhysicalAddress,
2367                 FirstTD);
2368 
2369     TD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2370     TD->NextHcdTD = EhciEndpoint->HcdTailP;
2371 
2372     EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2373 
2374     ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL);
2375     ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL);
2376 
2377     EHCI_EnablePeriodicList(EhciExtension);
2378 
2379     return MP_STATUS_SUCCESS;
2380 }
2381 
2382 MPSTATUS
2383 NTAPI
2384 EHCI_SubmitTransfer(IN PVOID ehciExtension,
2385                     IN PVOID ehciEndpoint,
2386                     IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2387                     IN PVOID ehciTransfer,
2388                     IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2389 {
2390     PEHCI_EXTENSION EhciExtension = ehciExtension;
2391     PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
2392     PEHCI_TRANSFER EhciTransfer = ehciTransfer;
2393     MPSTATUS MPStatus;
2394 
2395     DPRINT_EHCI("EHCI_SubmitTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2396                 EhciEndpoint,
2397                 EhciTransfer);
2398 
2399     RtlZeroMemory(EhciTransfer, sizeof(EHCI_TRANSFER));
2400 
2401     EhciTransfer->TransferParameters = TransferParameters;
2402     EhciTransfer->USBDStatus = USBD_STATUS_SUCCESS;
2403     EhciTransfer->EhciEndpoint = EhciEndpoint;
2404 
2405     switch (EhciEndpoint->EndpointProperties.TransferType)
2406     {
2407         case USBPORT_TRANSFER_TYPE_CONTROL:
2408             MPStatus = EHCI_ControlTransfer(EhciExtension,
2409                                             EhciEndpoint,
2410                                             TransferParameters,
2411                                             EhciTransfer,
2412                                             SgList);
2413             break;
2414 
2415         case USBPORT_TRANSFER_TYPE_BULK:
2416             MPStatus = EHCI_BulkTransfer(EhciExtension,
2417                                          EhciEndpoint,
2418                                          TransferParameters,
2419                                          EhciTransfer,
2420                                          SgList);
2421             break;
2422 
2423         case USBPORT_TRANSFER_TYPE_INTERRUPT:
2424             MPStatus = EHCI_InterruptTransfer(EhciExtension,
2425                                               EhciEndpoint,
2426                                               TransferParameters,
2427                                               EhciTransfer,
2428                                               SgList);
2429             break;
2430 
2431         default:
2432             DbgBreakPoint();
2433             MPStatus = MP_STATUS_NOT_SUPPORTED;
2434             break;
2435     }
2436 
2437     return MPStatus;
2438 }
2439 
2440 MPSTATUS
2441 NTAPI
2442 EHCI_SubmitIsoTransfer(IN PVOID ehciExtension,
2443                        IN PVOID ehciEndpoint,
2444                        IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2445                        IN PVOID ehciTransfer,
2446                        IN PVOID isoParameters)
2447 {
2448     DPRINT1("EHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n");
2449     return MP_STATUS_SUCCESS;
2450 }
2451 
2452 VOID
2453 NTAPI
2454 EHCI_AbortIsoTransfer(IN PEHCI_EXTENSION EhciExtension,
2455                       IN PEHCI_ENDPOINT EhciEndpoint,
2456                       IN PEHCI_TRANSFER EhciTransfer)
2457 {
2458     DPRINT1("EHCI_AbortIsoTransfer: UNIMPLEMENTED. FIXME\n");
2459 }
2460 
2461 VOID
2462 NTAPI
2463 EHCI_AbortAsyncTransfer(IN PEHCI_EXTENSION EhciExtension,
2464                         IN PEHCI_ENDPOINT EhciEndpoint,
2465                         IN PEHCI_TRANSFER EhciTransfer)
2466 {
2467     PEHCI_HCD_QH QH;
2468     PEHCI_HCD_TD TD;
2469     ULONG TransferLength;
2470     PEHCI_HCD_TD CurrentTD;
2471     PEHCI_TRANSFER CurrentTransfer;
2472     ULONG FirstTdPA;
2473     PEHCI_HCD_TD LastTD;
2474     PEHCI_HCD_TD PrevTD;
2475     ULONG NextTD;
2476 
2477     DPRINT("EHCI_AbortAsyncTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2478            EhciEndpoint,
2479            EhciTransfer);
2480 
2481     QH = EhciEndpoint->QH;
2482     TD = EhciEndpoint->HcdHeadP;
2483 
2484     ASSERT(EhciEndpoint->PendingTDs);
2485     EhciEndpoint->PendingTDs--;
2486 
2487     if (TD->EhciTransfer == EhciTransfer)
2488     {
2489         TransferLength = 0;
2490 
2491         while (TD != EhciEndpoint->HcdTailP &&
2492                TD->EhciTransfer == EhciTransfer)
2493         {
2494             TransferLength += TD->LengthThisTD - TD->HwTD.Token.TransferBytes;
2495 
2496             TD->HwTD.NextTD = 0;
2497             TD->HwTD.AlternateNextTD = 0;
2498 
2499             TD->TdFlags = 0;
2500             TD->EhciTransfer = NULL;
2501 
2502             EhciEndpoint->RemainTDs++;
2503 
2504             TD = TD->NextHcdTD;
2505         }
2506 
2507         if (TransferLength)
2508             EhciTransfer->TransferLen += TransferLength;
2509 
2510         QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
2511         QH->sqh.HwQH.NextTD = TD->PhysicalAddress;
2512         QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD;
2513 
2514         QH->sqh.HwQH.Token.TransferBytes = 0;
2515         QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
2516                                              EHCI_TOKEN_STATUS_HALTED);
2517 
2518         EhciEndpoint->HcdHeadP = TD;
2519     }
2520     else
2521     {
2522         DPRINT("EHCI_AbortAsyncTransfer: TD->EhciTransfer - %p\n", TD->EhciTransfer);
2523 
2524         CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(QH->sqh.HwQH.CurrentTD,
2525                                                              EhciExtension,
2526                                                              EhciEndpoint);
2527 
2528         CurrentTransfer = CurrentTD->EhciTransfer;
2529         TD = EhciEndpoint->HcdHeadP;
2530 
2531         while (TD && TD->EhciTransfer != EhciTransfer)
2532         {
2533             PrevTD = TD;
2534             TD = TD->NextHcdTD;
2535         }
2536 
2537         FirstTdPA = TD->PhysicalAddress;
2538 
2539         while (TD && TD->EhciTransfer == EhciTransfer)
2540         {
2541             TD->HwTD.NextTD = 0;
2542             TD->HwTD.AlternateNextTD = 0;
2543 
2544             TD->TdFlags = 0;
2545             TD->EhciTransfer = NULL;
2546 
2547             EhciEndpoint->RemainTDs++;
2548 
2549             TD = TD->NextHcdTD;
2550         }
2551 
2552         LastTD = TD;
2553         NextTD = LastTD->PhysicalAddress + FIELD_OFFSET(EHCI_HCD_TD, HwTD.NextTD);
2554 
2555         PrevTD->HwTD.NextTD = LastTD->PhysicalAddress;
2556         PrevTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2557 
2558         PrevTD->NextHcdTD = LastTD;
2559         PrevTD->AltNextHcdTD = LastTD;
2560 
2561         if (CurrentTransfer == EhciTransfer)
2562         {
2563             QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
2564 
2565             QH->sqh.HwQH.Token.Status = (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
2566             QH->sqh.HwQH.Token.TransferBytes = 0;
2567 
2568             QH->sqh.HwQH.NextTD = NextTD;
2569             QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
2570 
2571             return;
2572         }
2573 
2574         if (PrevTD->EhciTransfer == CurrentTransfer)
2575         {
2576             if (QH->sqh.HwQH.NextTD == FirstTdPA)
2577                 QH->sqh.HwQH.NextTD = NextTD;
2578 
2579             if (QH->sqh.HwQH.AlternateNextTD == FirstTdPA)
2580                 QH->sqh.HwQH.AlternateNextTD = NextTD;
2581 
2582             for (TD = EhciEndpoint->HcdHeadP;
2583                  TD;
2584                  TD = TD->NextHcdTD)
2585             {
2586                 if (TD->EhciTransfer == CurrentTransfer)
2587                 {
2588                     TD->HwTD.AlternateNextTD = NextTD;
2589                     TD->AltNextHcdTD = LastTD;
2590                 }
2591             }
2592         }
2593     }
2594 }
2595 
2596 VOID
2597 NTAPI
2598 EHCI_AbortTransfer(IN PVOID ehciExtension,
2599                    IN PVOID ehciEndpoint,
2600                    IN PVOID ehciTransfer,
2601                    IN PULONG CompletedLength)
2602 {
2603     PEHCI_EXTENSION EhciExtension = ehciExtension;
2604     PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
2605     PEHCI_TRANSFER EhciTransfer = ehciTransfer;
2606     ULONG TransferType;
2607 
2608     DPRINT("EHCI_AbortTransfer: EhciTransfer - %p, CompletedLength - %x\n",
2609            EhciTransfer,
2610            CompletedLength);
2611 
2612     TransferType = EhciEndpoint->EndpointProperties.TransferType;
2613 
2614     if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2615         EHCI_AbortIsoTransfer(EhciExtension, EhciEndpoint, EhciTransfer);
2616     else
2617         EHCI_AbortAsyncTransfer(EhciExtension, EhciEndpoint, EhciTransfer);
2618 }
2619 
2620 ULONG
2621 NTAPI
2622 EHCI_GetEndpointState(IN PVOID ehciExtension,
2623                       IN PVOID ehciEndpoint)
2624 {
2625     DPRINT1("EHCI_GetEndpointState: UNIMPLEMENTED. FIXME\n");
2626     return 0;
2627 }
2628 
2629 VOID
2630 NTAPI
2631 EHCI_RemoveQhFromPeriodicList(IN PEHCI_EXTENSION EhciExtension,
2632                               IN PEHCI_ENDPOINT EhciEndpoint)
2633 {
2634     PEHCI_HCD_QH QH;
2635     PEHCI_HCD_QH NextHead;
2636     ULONG NextQhPA;
2637     PEHCI_HCD_QH PrevHead;
2638 
2639     QH = EhciEndpoint->QH;
2640 
2641     if (!(QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE))
2642         return;
2643 
2644     DPRINT("EHCI_RemoveQhFromPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n",
2645            EhciEndpoint,
2646            QH,
2647            EhciEndpoint->StaticQH);
2648 
2649     NextHead = QH->sqh.NextHead;
2650     PrevHead = QH->sqh.PrevHead;
2651 
2652     PrevHead->sqh.NextHead = NextHead;
2653 
2654     if (NextHead)
2655     {
2656         if (!(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC))
2657             NextHead->sqh.PrevHead = PrevHead;
2658 
2659         NextQhPA = NextHead->sqh.PhysicalAddress;
2660         NextQhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2661         NextQhPA |= (EHCI_LINK_TYPE_QH << 1);
2662 
2663         PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextQhPA;
2664     }
2665     else
2666     {
2667         PrevHead->sqh.HwQH.HorizontalLink.Terminate = 1;
2668     }
2669 
2670     QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE;
2671 
2672     QH->sqh.NextHead = NULL;
2673     QH->sqh.PrevHead = NULL;
2674 }
2675 
2676 VOID
2677 NTAPI
2678 EHCI_RemoveQhFromAsyncList(IN PEHCI_EXTENSION EhciExtension,
2679                            IN PEHCI_HCD_QH QH)
2680 {
2681     PEHCI_HCD_QH NextHead;
2682     ULONG NextHeadPA;
2683     PEHCI_HCD_QH PrevHead;
2684     PEHCI_STATIC_QH AsyncHead;
2685     ULONG AsyncHeadPA;
2686 
2687     DPRINT("EHCI_RemoveQhFromAsyncList: QH - %p\n", QH);
2688 
2689     if (QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE)
2690     {
2691         NextHead = QH->sqh.NextHead;
2692         PrevHead = QH->sqh.PrevHead;
2693 
2694         AsyncHead = EhciExtension->AsyncHead;
2695 
2696         AsyncHeadPA = AsyncHead->PhysicalAddress;
2697         AsyncHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2698         AsyncHeadPA |= (EHCI_LINK_TYPE_QH << 1);
2699 
2700         NextHeadPA = NextHead->sqh.PhysicalAddress;
2701         NextHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2702         NextHeadPA |= (EHCI_LINK_TYPE_QH << 1);
2703 
2704         PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextHeadPA;
2705 
2706         PrevHead->sqh.NextHead = NextHead;
2707         NextHead->sqh.PrevHead = PrevHead;
2708 
2709         EHCI_FlushAsyncCache(EhciExtension);
2710 
2711         if (READ_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase) ==
2712             QH->sqh.PhysicalAddress)
2713         {
2714             WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase,
2715                                  AsyncHeadPA);
2716         }
2717 
2718         QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE;
2719     }
2720 }
2721 
2722 VOID
2723 NTAPI
2724 EHCI_InsertQhInPeriodicList(IN PEHCI_EXTENSION EhciExtension,
2725                             IN PEHCI_ENDPOINT EhciEndpoint)
2726 {
2727     PEHCI_STATIC_QH StaticQH;
2728     PEHCI_HCD_QH QH;
2729     ULONG QhPA;
2730     PEHCI_HCD_QH NextHead;
2731     PEHCI_HCD_QH PrevHead;
2732 
2733     QH = EhciEndpoint->QH;
2734     StaticQH = EhciEndpoint->StaticQH;
2735 
2736     ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0);
2737     ASSERT(StaticQH->QhFlags & EHCI_QH_FLAG_STATIC);
2738 
2739     NextHead = StaticQH->NextHead;
2740 
2741     QH->sqh.Period = EhciEndpoint->EndpointProperties.Period;
2742     QH->sqh.Ordinal = EhciEndpoint->EndpointProperties.Reserved6;
2743 
2744     DPRINT("EHCI_InsertQhInPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n",
2745            EhciEndpoint,
2746            QH,
2747            EhciEndpoint->StaticQH);
2748 
2749     PrevHead = (PEHCI_HCD_QH)StaticQH;
2750 
2751     if ((StaticQH->QhFlags & EHCI_QH_FLAG_STATIC) &&
2752         (!NextHead || (NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC)))
2753     {
2754         DPRINT("EHCI_InsertQhInPeriodicList: StaticQH - %p, StaticQH->NextHead - %p\n",
2755                StaticQH,
2756                StaticQH->NextHead);
2757     }
2758     else
2759     {
2760         while (NextHead &&
2761                !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC) &&
2762                QH->sqh.Ordinal > NextHead->sqh.Ordinal)
2763         {
2764             PrevHead = NextHead;
2765             NextHead = NextHead->sqh.NextHead;
2766         }
2767     }
2768 
2769     QH->sqh.NextHead = NextHead;
2770     QH->sqh.PrevHead = PrevHead;
2771 
2772     if (NextHead && !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC))
2773         NextHead->sqh.PrevHead = QH;
2774 
2775     QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE;
2776     QH->sqh.HwQH.HorizontalLink = PrevHead->sqh.HwQH.HorizontalLink;
2777 
2778     PrevHead->sqh.NextHead = QH;
2779 
2780     QhPA = QH->sqh.PhysicalAddress;
2781     QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2782     QhPA |= (EHCI_LINK_TYPE_QH << 1);
2783 
2784     PrevHead->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
2785 }
2786 
2787 VOID
2788 NTAPI
2789 EHCI_InsertQhInAsyncList(IN PEHCI_EXTENSION EhciExtension,
2790                          IN PEHCI_HCD_QH QH)
2791 {
2792     PEHCI_STATIC_QH AsyncHead;
2793     ULONG QhPA;
2794     PEHCI_HCD_QH NextHead;
2795 
2796     DPRINT("EHCI_InsertQhInAsyncList: QH - %p\n", QH);
2797 
2798     ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0);
2799     ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_NUKED) == 0);
2800 
2801     AsyncHead = EhciExtension->AsyncHead;
2802     NextHead = AsyncHead->NextHead;
2803 
2804     QH->sqh.HwQH.HorizontalLink = AsyncHead->HwQH.HorizontalLink;
2805     QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE;
2806     QH->sqh.NextHead = NextHead;
2807     QH->sqh.PrevHead = (PEHCI_HCD_QH)AsyncHead;
2808 
2809     NextHead->sqh.PrevHead = QH;
2810 
2811     QhPA = QH->sqh.PhysicalAddress;
2812     QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2813     QhPA |= (EHCI_LINK_TYPE_QH << 1);
2814 
2815     AsyncHead->HwQH.HorizontalLink.AsULONG = QhPA;
2816 
2817     AsyncHead->NextHead = QH;
2818 }
2819 
2820 VOID
2821 NTAPI
2822 EHCI_SetIsoEndpointState(IN PEHCI_EXTENSION EhciExtension,
2823                          IN PEHCI_ENDPOINT EhciEndpoint,
2824                          IN ULONG EndpointState)
2825 {
2826     DPRINT1("EHCI_SetIsoEndpointState: UNIMPLEMENTED. FIXME\n");
2827 }
2828 
2829 VOID
2830 NTAPI
2831 EHCI_SetAsyncEndpointState(IN PEHCI_EXTENSION EhciExtension,
2832                            IN PEHCI_ENDPOINT EhciEndpoint,
2833                            IN ULONG EndpointState)
2834 {
2835     PEHCI_HCD_QH QH;
2836     ULONG TransferType;
2837 
2838     DPRINT("EHCI_SetAsyncEndpointState: EhciEndpoint - %p, EndpointState - %x\n",
2839             EhciEndpoint,
2840             EndpointState);
2841 
2842     QH = EhciEndpoint->QH;
2843 
2844     TransferType = EhciEndpoint->EndpointProperties.TransferType;
2845 
2846     switch (EndpointState)
2847     {
2848         case USBPORT_ENDPOINT_PAUSED:
2849             if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2850                 EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint);
2851             else
2852                 EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH);
2853 
2854             break;
2855 
2856         case USBPORT_ENDPOINT_ACTIVE:
2857             if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2858                 EHCI_InsertQhInPeriodicList(EhciExtension, EhciEndpoint);
2859             else
2860                 EHCI_InsertQhInAsyncList(EhciExtension, EhciEndpoint->QH);
2861 
2862             break;
2863 
2864         case USBPORT_ENDPOINT_REMOVE:
2865             QH->sqh.QhFlags |= EHCI_QH_FLAG_CLOSED;
2866 
2867             if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2868                 EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint);
2869             else
2870                 EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH);
2871 
2872             break;
2873 
2874         default:
2875             DbgBreakPoint();
2876             break;
2877     }
2878 
2879     EhciEndpoint->EndpointState = EndpointState;
2880 }
2881 
2882 VOID
2883 NTAPI
2884 EHCI_SetEndpointState(IN PVOID ehciExtension,
2885                       IN PVOID ehciEndpoint,
2886                       IN ULONG EndpointState)
2887 {
2888     PEHCI_ENDPOINT EhciEndpoint;
2889     ULONG TransferType;
2890 
2891     DPRINT("EHCI_SetEndpointState: ... \n");
2892 
2893     EhciEndpoint = ehciEndpoint;
2894     TransferType = EhciEndpoint->EndpointProperties.TransferType;
2895 
2896     if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2897         TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2898         TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2899     {
2900          EHCI_SetAsyncEndpointState((PEHCI_EXTENSION)ehciExtension,
2901                                     EhciEndpoint,
2902                                     EndpointState);
2903     }
2904     else if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2905     {
2906         EHCI_SetIsoEndpointState((PEHCI_EXTENSION)ehciExtension,
2907                                  EhciEndpoint,
2908                                  EndpointState);
2909     }
2910     else
2911     {
2912         RegPacket.UsbPortBugCheck(ehciExtension);
2913     }
2914 }
2915 
2916 VOID
2917 NTAPI
2918 EHCI_InterruptNextSOF(IN PVOID ehciExtension)
2919 {
2920     PEHCI_EXTENSION EhciExtension = ehciExtension;
2921 
2922     DPRINT_EHCI("EHCI_InterruptNextSOF: ... \n");
2923 
2924     RegPacket.UsbPortInvalidateController(EhciExtension,
2925                                           USBPORT_INVALIDATE_CONTROLLER_SOFT_INTERRUPT);
2926 }
2927 
2928 USBD_STATUS
2929 NTAPI
2930 EHCI_GetErrorFromTD(IN PEHCI_HCD_TD TD)
2931 {
2932     EHCI_TD_TOKEN Token;
2933 
2934     DPRINT_EHCI("EHCI_GetErrorFromTD: ... \n");
2935 
2936     ASSERT(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED);
2937 
2938     Token = TD->HwTD.Token;
2939 
2940     if (Token.Status & EHCI_TOKEN_STATUS_TRANSACTION_ERROR)
2941     {
2942         DPRINT("EHCI_GetErrorFromTD: TD - %p, TRANSACTION_ERROR\n", TD);
2943         return USBD_STATUS_XACT_ERROR;
2944     }
2945 
2946     if (Token.Status & EHCI_TOKEN_STATUS_BABBLE_DETECTED)
2947     {
2948         DPRINT("EHCI_GetErrorFromTD: TD - %p, BABBLE_DETECTED\n", TD);
2949         return USBD_STATUS_BABBLE_DETECTED;
2950     }
2951 
2952     if (Token.Status & EHCI_TOKEN_STATUS_DATA_BUFFER_ERROR)
2953     {
2954         DPRINT("EHCI_GetErrorFromTD: TD - %p, DATA_BUFFER_ERROR\n", TD);
2955         return USBD_STATUS_DATA_BUFFER_ERROR;
2956     }
2957 
2958     if (Token.Status & EHCI_TOKEN_STATUS_MISSED_MICROFRAME)
2959     {
2960         DPRINT("EHCI_GetErrorFromTD: TD - %p, MISSED_MICROFRAME\n", TD);
2961         return USBD_STATUS_XACT_ERROR;
2962     }
2963 
2964     DPRINT("EHCI_GetErrorFromTD: TD - %p, STALL_PID\n", TD);
2965     return USBD_STATUS_STALL_PID;
2966 }
2967 
2968 VOID
2969 NTAPI
2970 EHCI_ProcessDoneAsyncTd(IN PEHCI_EXTENSION EhciExtension,
2971                         IN PEHCI_HCD_TD TD)
2972 {
2973     PEHCI_TRANSFER EhciTransfer;
2974     PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
2975     ULONG TransferType;
2976     PEHCI_ENDPOINT EhciEndpoint;
2977     ULONG LengthTransfered;
2978     USBD_STATUS USBDStatus;
2979     PEHCI_HW_REGISTERS OperationalRegs;
2980     EHCI_USB_COMMAND Command;
2981 
2982     DPRINT_EHCI("EHCI_ProcessDoneAsyncTd: TD - %p\n", TD);
2983 
2984     EhciTransfer = TD->EhciTransfer;
2985 
2986     TransferParameters = EhciTransfer->TransferParameters;
2987     EhciTransfer->PendingTDs--;
2988 
2989     EhciEndpoint = EhciTransfer->EhciEndpoint;
2990 
2991     if (!(TD->TdFlags & EHCI_HCD_TD_FLAG_ACTIVE))
2992     {
2993 
2994         if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED)
2995             USBDStatus = EHCI_GetErrorFromTD(TD);
2996         else
2997             USBDStatus = USBD_STATUS_SUCCESS;
2998 
2999         LengthTransfered = TD->LengthThisTD - TD->HwTD.Token.TransferBytes;
3000 
3001         if (TD->HwTD.Token.PIDCode != EHCI_TD_TOKEN_PID_SETUP)
3002             EhciTransfer->TransferLen += LengthTransfered;
3003 
3004         if (USBDStatus != USBD_STATUS_SUCCESS)
3005             EhciTransfer->USBDStatus = USBDStatus;
3006     }
3007 
3008     TD->HwTD.NextTD = 0;
3009     TD->HwTD.AlternateNextTD = 0;
3010 
3011     TD->TdFlags = 0;
3012     TD->EhciTransfer = NULL;
3013 
3014     EhciEndpoint->RemainTDs++;
3015 
3016     if (EhciTransfer->PendingTDs == 0)
3017     {
3018         EhciEndpoint->PendingTDs--;
3019 
3020         TransferType = EhciEndpoint->EndpointProperties.TransferType;
3021 
3022         if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
3023             TransferType == USBPORT_TRANSFER_TYPE_BULK)
3024         {
3025             EhciExtension->PendingTransfers--;
3026 
3027             if (EhciExtension->PendingTransfers == 0)
3028             {
3029                 OperationalRegs = EhciExtension->OperationalRegs;
3030                 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
3031 
3032                 if (!Command.InterruptAdvanceDoorbell &&
3033                     (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT))
3034                 {
3035                     EHCI_DisableAsyncList(EhciExtension);
3036                 }
3037             }
3038         }
3039 
3040         RegPacket.UsbPortCompleteTransfer(EhciExtension,
3041                                           EhciEndpoint,
3042                                           TransferParameters,
3043                                           EhciTransfer->USBDStatus,
3044                                           EhciTransfer->TransferLen);
3045     }
3046 }
3047 
3048 VOID
3049 NTAPI
3050 EHCI_PollActiveAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3051                              IN PEHCI_ENDPOINT EhciEndpoint)
3052 {
3053     PEHCI_HCD_QH QH;
3054     PEHCI_HCD_TD TD;
3055     PEHCI_HCD_TD CurrentTD;
3056     ULONG CurrentTDPhys;
3057     BOOLEAN IsScheduled;
3058 
3059     DPRINT_EHCI("EHCI_PollActiveAsyncEndpoint: ... \n");
3060 
3061     QH = EhciEndpoint->QH;
3062 
3063     CurrentTDPhys = QH->sqh.HwQH.CurrentTD & LINK_POINTER_MASK;
3064     ASSERT(CurrentTDPhys);
3065 
3066     CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTDPhys,
3067                                                          EhciExtension,
3068                                                          EhciEndpoint);
3069 
3070     if (CurrentTD == EhciEndpoint->DmaBufferVA)
3071         return;
3072 
3073     IsScheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE;
3074 
3075     if (!EHCI_HardwarePresent(EhciExtension, 0))
3076         IsScheduled = 0;
3077 
3078     TD = EhciEndpoint->HcdHeadP;
3079 
3080     if (TD == CurrentTD)
3081     {
3082         if (TD != EhciEndpoint->HcdTailP &&
3083             !(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE))
3084         {
3085             if (TD->NextHcdTD && TD->HwTD.NextTD != TD->NextHcdTD->PhysicalAddress)
3086                 TD->HwTD.NextTD = TD->NextHcdTD->PhysicalAddress;
3087 
3088             if (TD->AltNextHcdTD &&
3089                 TD->HwTD.AlternateNextTD != TD->AltNextHcdTD->PhysicalAddress)
3090             {
3091                 TD->HwTD.AlternateNextTD = TD->AltNextHcdTD->PhysicalAddress;
3092             }
3093 
3094             if (QH->sqh.HwQH.CurrentTD == TD->PhysicalAddress &&
3095                 !(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) &&
3096                 (QH->sqh.HwQH.NextTD != TD->HwTD.NextTD ||
3097                  QH->sqh.HwQH.AlternateNextTD != TD->HwTD.AlternateNextTD))
3098             {
3099                 QH->sqh.HwQH.NextTD = TD->HwTD.NextTD;
3100                 QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD;
3101             }
3102 
3103             EHCI_InterruptNextSOF(EhciExtension);
3104         }
3105     }
3106     else
3107     {
3108         while (TD != CurrentTD)
3109         {
3110             ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0);
3111 
3112             TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3113 
3114             if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3115                 TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3116 
3117             InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3118             TD = TD->NextHcdTD;
3119         }
3120     }
3121 
3122     if (CurrentTD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3123     {
3124         ASSERT(TD != NULL);
3125         EhciEndpoint->HcdHeadP = TD;
3126         return;
3127     }
3128 
3129     if ((CurrentTD->NextHcdTD != EhciEndpoint->HcdTailP) &&
3130         (CurrentTD->AltNextHcdTD != EhciEndpoint->HcdTailP ||
3131          CurrentTD->HwTD.Token.TransferBytes == 0))
3132     {
3133         ASSERT(TD != NULL);
3134         EhciEndpoint->HcdHeadP = TD;
3135         return;
3136     }
3137 
3138     if (IsScheduled)
3139     {
3140         EHCI_LockQH(EhciExtension,
3141                     QH,
3142                     EhciEndpoint->EndpointProperties.TransferType);
3143     }
3144 
3145     QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
3146 
3147     CurrentTD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3148     InsertTailList(&EhciEndpoint->ListTDs, &CurrentTD->DoneLink);
3149 
3150     if (CurrentTD->HwTD.Token.TransferBytes &&
3151         CurrentTD->AltNextHcdTD == EhciEndpoint->HcdTailP)
3152     {
3153         TD = CurrentTD->NextHcdTD;
3154 
3155         while (TD != EhciEndpoint->HcdTailP)
3156         {
3157             TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3158             InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3159             TD = TD->NextHcdTD;
3160         }
3161     }
3162 
3163     QH->sqh.HwQH.CurrentTD = EhciEndpoint->HcdTailP->PhysicalAddress;
3164     QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
3165     QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
3166     QH->sqh.HwQH.Token.TransferBytes = 0;
3167 
3168     EhciEndpoint->HcdHeadP = EhciEndpoint->HcdTailP;
3169 
3170     if (IsScheduled)
3171         EHCI_UnlockQH(EhciExtension, QH);
3172 }
3173 
3174 VOID
3175 NTAPI
3176 EHCI_PollHaltedAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3177                              IN PEHCI_ENDPOINT EhciEndpoint)
3178 {
3179     PEHCI_HCD_QH QH;
3180     PEHCI_HCD_TD CurrentTD;
3181     ULONG CurrentTdPA;
3182     PEHCI_HCD_TD TD;
3183     PEHCI_TRANSFER Transfer;
3184     BOOLEAN IsScheduled;
3185 
3186     DPRINT("EHCI_PollHaltedAsyncEndpoint: EhciEndpoint - %p\n", EhciEndpoint);
3187 
3188     QH = EhciEndpoint->QH;
3189     EHCI_DumpHwQH(QH);
3190 
3191     CurrentTdPA = QH->sqh.HwQH.CurrentTD & LINK_POINTER_MASK;
3192     ASSERT(CurrentTdPA);
3193 
3194     IsScheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE;
3195 
3196     if (!EHCI_HardwarePresent(EhciExtension, 0))
3197         IsScheduled = 0;
3198 
3199     CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTdPA,
3200                                                          EhciExtension,
3201                                                          EhciEndpoint);
3202 
3203     DPRINT("EHCI_PollHaltedAsyncEndpoint: CurrentTD - %p\n", CurrentTD);
3204 
3205     if (CurrentTD == EhciEndpoint->DmaBufferVA)
3206         return;
3207 
3208     ASSERT(EhciEndpoint->HcdTailP != CurrentTD);
3209 
3210     if (IsScheduled)
3211     {
3212         EHCI_LockQH(EhciExtension,
3213                     QH,
3214                     EhciEndpoint->EndpointProperties.TransferType);
3215     }
3216 
3217     TD = EhciEndpoint->HcdHeadP;
3218 
3219     while (TD != CurrentTD)
3220     {
3221         DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD);
3222 
3223         ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0);
3224 
3225         if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3226             TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3227 
3228         TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3229 
3230         InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3231 
3232         TD = TD->NextHcdTD;
3233     }
3234 
3235     TD = CurrentTD;
3236 
3237     Transfer = CurrentTD->EhciTransfer;
3238 
3239     do
3240     {
3241         DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD);
3242 
3243         if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3244             TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3245 
3246         TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3247 
3248         InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3249 
3250         TD = TD->NextHcdTD;
3251     }
3252     while (TD->EhciTransfer == Transfer);
3253 
3254     EhciEndpoint->HcdHeadP = TD;
3255 
3256     QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
3257     QH->sqh.HwQH.NextTD = TD->PhysicalAddress;
3258     QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
3259     QH->sqh.HwQH.Token.TransferBytes = 0;
3260 
3261     if (IsScheduled)
3262         EHCI_UnlockQH(EhciExtension, QH);
3263 
3264     if (EhciEndpoint->EndpointStatus & USBPORT_ENDPOINT_CONTROL)
3265     {
3266         EhciEndpoint->EndpointStatus &= ~USBPORT_ENDPOINT_HALT;
3267         QH->sqh.HwQH.Token.ErrorCounter = 0;
3268         QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
3269                                               EHCI_TOKEN_STATUS_HALTED);
3270 
3271     }
3272 }
3273 
3274 VOID
3275 NTAPI
3276 EHCI_PollAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3277                        IN PEHCI_ENDPOINT EhciEndpoint)
3278 {
3279     PEHCI_HCD_QH QH;
3280     PLIST_ENTRY DoneList;
3281     PEHCI_HCD_TD TD;
3282 
3283     //DPRINT_EHCI("EHCI_PollAsyncEndpoint: EhciEndpoint - %p\n", EhciEndpoint);
3284 
3285     if (!EhciEndpoint->PendingTDs)
3286         return;
3287 
3288     QH = EhciEndpoint->QH;
3289 
3290     if (QH->sqh.QhFlags & EHCI_QH_FLAG_CLOSED)
3291         return;
3292 
3293     if (QH->sqh.HwQH.Token.Status & EHCI_TOKEN_STATUS_ACTIVE ||
3294         !(QH->sqh.HwQH.Token.Status & EHCI_TOKEN_STATUS_HALTED))
3295     {
3296         EHCI_PollActiveAsyncEndpoint(EhciExtension, EhciEndpoint);
3297     }
3298     else
3299     {
3300         EhciEndpoint->EndpointStatus |= USBPORT_ENDPOINT_HALT;
3301         EHCI_PollHaltedAsyncEndpoint(EhciExtension, EhciEndpoint);
3302     }
3303 
3304     DoneList = &EhciEndpoint->ListTDs;
3305 
3306     while (!IsListEmpty(DoneList))
3307     {
3308         TD = CONTAINING_RECORD(DoneList->Flink,
3309                                EHCI_HCD_TD,
3310                                DoneLink);
3311 
3312         RemoveHeadList(DoneList);
3313 
3314         ASSERT((TD->TdFlags & (EHCI_HCD_TD_FLAG_PROCESSED |
3315                                EHCI_HCD_TD_FLAG_DONE)));
3316 
3317         EHCI_ProcessDoneAsyncTd(EhciExtension, TD);
3318     }
3319 }
3320 
3321 VOID
3322 NTAPI
3323 EHCI_PollIsoEndpoint(IN PEHCI_EXTENSION EhciExtension,
3324                      IN PEHCI_ENDPOINT EhciEndpoint)
3325 {
3326     DPRINT1("EHCI_PollIsoEndpoint: UNIMPLEMENTED. FIXME\n");
3327 }
3328 
3329 VOID
3330 NTAPI
3331 EHCI_PollEndpoint(IN PVOID ehciExtension,
3332                   IN PVOID ehciEndpoint)
3333 {
3334     PEHCI_EXTENSION EhciExtension = ehciExtension;
3335     PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
3336     ULONG TransferType;
3337 
3338     //DPRINT_EHCI("EHCI_PollEndpoint: EhciEndpoint - %p\n", EhciEndpoint);
3339 
3340     TransferType = EhciEndpoint->EndpointProperties.TransferType;
3341 
3342     if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
3343         EHCI_PollIsoEndpoint(EhciExtension, EhciEndpoint);
3344     else
3345         EHCI_PollAsyncEndpoint(EhciExtension, EhciEndpoint);
3346 }
3347 
3348 VOID
3349 NTAPI
3350 EHCI_CheckController(IN PVOID ehciExtension)
3351 {
3352     PEHCI_EXTENSION EhciExtension = ehciExtension;
3353 
3354     //DPRINT_EHCI("EHCI_CheckController: ... \n");
3355 
3356     if (EhciExtension->IsStarted)
3357         EHCI_HardwarePresent(EhciExtension, TRUE);
3358 }
3359 
3360 ULONG
3361 NTAPI
3362 EHCI_Get32BitFrameNumber(IN PVOID ehciExtension)
3363 {
3364     PEHCI_EXTENSION EhciExtension = ehciExtension;
3365     ULONG FrameIdx;
3366     ULONG FrameIndex;
3367     ULONG FrameNumber;
3368 
3369     //DPRINT_EHCI("EHCI_Get32BitFrameNumber: EhciExtension - %p\n", EhciExtension);
3370 
3371     FrameIdx = EhciExtension->FrameIndex;
3372     FrameIndex = READ_REGISTER_ULONG(&EhciExtension->OperationalRegs->FrameIndex);
3373 
3374     FrameNumber = (USHORT)FrameIdx ^ ((FrameIndex / EHCI_MICROFRAMES) & EHCI_FRINDEX_FRAME_MASK);
3375     FrameNumber &= EHCI_FRAME_LIST_MAX_ENTRIES;
3376     FrameNumber += FrameIndex | ((FrameIndex / EHCI_MICROFRAMES) & EHCI_FRINDEX_INDEX_MASK);
3377 
3378     return FrameNumber;
3379 }
3380 
3381 VOID
3382 NTAPI
3383 EHCI_EnableInterrupts(IN PVOID ehciExtension)
3384 {
3385     PEHCI_EXTENSION EhciExtension = ehciExtension;
3386 
3387     DPRINT("EHCI_EnableInterrupts: EhciExtension->InterruptMask - %x\n",
3388            EhciExtension->InterruptMask.AsULONG);
3389 
3390     WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG,
3391                          EhciExtension->InterruptMask.AsULONG);
3392 }
3393 
3394 VOID
3395 NTAPI
3396 EHCI_DisableInterrupts(IN PVOID ehciExtension)
3397 {
3398     PEHCI_EXTENSION EhciExtension = ehciExtension;
3399 
3400     DPRINT("EHCI_DisableInterrupts: ... \n");
3401 
3402     WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG,
3403                          0);
3404 }
3405 
3406 VOID
3407 NTAPI
3408 EHCI_PollController(IN PVOID ehciExtension)
3409 {
3410     PEHCI_EXTENSION EhciExtension = ehciExtension;
3411     PEHCI_HW_REGISTERS OperationalRegs;
3412     ULONG Port;
3413     EHCI_PORT_STATUS_CONTROL PortSC;
3414 
3415     DPRINT_EHCI("EHCI_PollController: ... \n");
3416 
3417     OperationalRegs = EhciExtension->OperationalRegs;
3418 
3419     if (!(EhciExtension->Flags & EHCI_FLAGS_CONTROLLER_SUSPEND))
3420     {
3421         RegPacket.UsbPortInvalidateRootHub(EhciExtension);
3422         return;
3423     }
3424 
3425     if (EhciExtension->NumberOfPorts)
3426     {
3427         for (Port = 0; Port < EhciExtension->NumberOfPorts; Port++)
3428         {
3429             PortSC.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->PortControl[Port].AsULONG);
3430 
3431             if (PortSC.ConnectStatusChange)
3432                 RegPacket.UsbPortInvalidateRootHub(EhciExtension);
3433         }
3434     }
3435 }
3436 
3437 VOID
3438 NTAPI
3439 EHCI_SetEndpointDataToggle(IN PVOID ehciExtension,
3440                            IN PVOID ehciEndpoint,
3441                            IN ULONG DataToggle)
3442 {
3443     PEHCI_ENDPOINT EhciEndpoint;
3444     ULONG TransferType;
3445 
3446     EhciEndpoint = ehciEndpoint;
3447 
3448     DPRINT("EHCI_SetEndpointDataToggle: EhciEndpoint - %p, DataToggle - %x\n",
3449                 EhciEndpoint,
3450                 DataToggle);
3451 
3452     TransferType = EhciEndpoint->EndpointProperties.TransferType;
3453 
3454     if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
3455         TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
3456     {
3457         EhciEndpoint->QH->sqh.HwQH.Token.DataToggle = DataToggle;
3458     }
3459 }
3460 
3461 ULONG
3462 NTAPI
3463 EHCI_GetEndpointStatus(IN PVOID ehciExtension,
3464                        IN PVOID ehciEndpoint)
3465 {
3466     PEHCI_ENDPOINT EhciEndpoint;
3467     ULONG TransferType;
3468     ULONG EndpointStatus = USBPORT_ENDPOINT_RUN;
3469 
3470     EhciEndpoint = ehciEndpoint;
3471 
3472     DPRINT("EHCI_GetEndpointStatus: EhciEndpoint - %p\n", EhciEndpoint);
3473 
3474     TransferType = EhciEndpoint->EndpointProperties.TransferType;
3475 
3476     if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
3477         return EndpointStatus;
3478 
3479     if (EhciEndpoint->EndpointStatus & USBPORT_ENDPOINT_HALT)
3480         EndpointStatus = USBPORT_ENDPOINT_HALT;
3481 
3482     return EndpointStatus;
3483 }
3484 
3485 VOID
3486 NTAPI
3487 EHCI_SetEndpointStatus(IN PVOID ehciExtension,
3488                        IN PVOID ehciEndpoint,
3489                        IN ULONG EndpointStatus)
3490 {
3491     PEHCI_ENDPOINT EhciEndpoint;
3492     ULONG TransferType;
3493     PEHCI_HCD_QH QH;
3494 
3495     EhciEndpoint = ehciEndpoint;
3496 
3497     DPRINT("EHCI_SetEndpointStatus: EhciEndpoint - %p, EndpointStatus - %x\n",
3498                 EhciEndpoint,
3499                 EndpointStatus);
3500 
3501     TransferType = EhciEndpoint->EndpointProperties.TransferType;
3502 
3503     if (TransferType != USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
3504     {
3505 
3506         if (EndpointStatus == USBPORT_ENDPOINT_RUN)
3507         {
3508             EhciEndpoint->EndpointStatus &= ~USBPORT_ENDPOINT_HALT;
3509 
3510             QH = EhciEndpoint->QH;
3511             QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_HALTED;
3512 
3513             return;
3514         }
3515 
3516         if (EndpointStatus == USBPORT_ENDPOINT_HALT)
3517             DbgBreakPoint();
3518     }
3519 }
3520 
3521 VOID
3522 NTAPI
3523 EHCI_ResetController(IN PVOID ehciExtension)
3524 {
3525     DPRINT1("EHCI_ResetController: UNIMPLEMENTED. FIXME\n");
3526 }
3527 
3528 MPSTATUS
3529 NTAPI
3530 EHCI_StartSendOnePacket(IN PVOID ehciExtension,
3531                         IN PVOID PacketParameters,
3532                         IN PVOID Data,
3533                         IN PULONG pDataLength,
3534                         IN PVOID BufferVA,
3535                         IN PVOID BufferPA,
3536                         IN ULONG BufferLength,
3537                         IN USBD_STATUS * pUSBDStatus)
3538 {
3539     DPRINT1("EHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n");
3540     return MP_STATUS_SUCCESS;
3541 }
3542 
3543 MPSTATUS
3544 NTAPI
3545 EHCI_EndSendOnePacket(IN PVOID ehciExtension,
3546                       IN PVOID PacketParameters,
3547                       IN PVOID Data,
3548                       IN PULONG pDataLength,
3549                       IN PVOID BufferVA,
3550                       IN PVOID BufferPA,
3551                       IN ULONG BufferLength,
3552                       IN USBD_STATUS * pUSBDStatus)
3553 {
3554     DPRINT1("EHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n");
3555     return MP_STATUS_SUCCESS;
3556 }
3557 
3558 MPSTATUS
3559 NTAPI
3560 EHCI_PassThru(IN PVOID ehciExtension,
3561               IN PVOID passThruParameters,
3562               IN ULONG ParameterLength,
3563               IN PVOID pParameters)
3564 {
3565     DPRINT1("EHCI_PassThru: UNIMPLEMENTED. FIXME\n");
3566     return MP_STATUS_SUCCESS;
3567 }
3568 
3569 VOID
3570 NTAPI
3571 EHCI_RebalanceEndpoint(IN PVOID ohciExtension,
3572                        IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
3573                        IN PVOID ohciEndpoint)
3574 {
3575     DPRINT1("EHCI_RebalanceEndpoint: UNIMPLEMENTED. FIXME\n");
3576 }
3577 
3578 VOID
3579 NTAPI
3580 EHCI_FlushInterrupts(IN PVOID ehciExtension)
3581 {
3582     PEHCI_EXTENSION EhciExtension = ehciExtension;
3583     PEHCI_HW_REGISTERS OperationalRegs;
3584     EHCI_USB_STATUS Status;
3585 
3586     DPRINT("EHCI_FlushInterrupts: ... \n");
3587 
3588     OperationalRegs = EhciExtension->OperationalRegs;
3589 
3590     Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
3591     WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, Status.AsULONG);
3592 }
3593 
3594 VOID
3595 NTAPI
3596 EHCI_TakePortControl(IN PVOID ohciExtension)
3597 {
3598     DPRINT1("EHCI_TakePortControl: UNIMPLEMENTED. FIXME\n");
3599 }
3600 
3601 VOID
3602 NTAPI
3603 EHCI_Unload(IN PDRIVER_OBJECT DriverObject)
3604 {
3605 #if DBG
3606     DPRINT1("EHCI_Unload: Not supported\n");
3607 #endif
3608     return;
3609 }
3610 
3611 NTSTATUS
3612 NTAPI
3613 DriverEntry(IN PDRIVER_OBJECT DriverObject,
3614             IN PUNICODE_STRING RegistryPath)
3615 {
3616     DPRINT("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n",
3617            DriverObject,
3618            RegistryPath);
3619 
3620     if (USBPORT_GetHciMn() != USBPORT_HCI_MN)
3621         return STATUS_INSUFFICIENT_RESOURCES;
3622 
3623     RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET));
3624 
3625     RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_EHCI;
3626 
3627     RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT |
3628                               USB_MINIPORT_FLAGS_MEMORY_IO |
3629                               USB_MINIPORT_FLAGS_USB2 |
3630                               USB_MINIPORT_FLAGS_POLLING |
3631                               USB_MINIPORT_FLAGS_WAKE_SUPPORT;
3632 
3633     RegPacket.MiniPortBusBandwidth = TOTAL_USB20_BUS_BANDWIDTH;
3634 
3635     RegPacket.MiniPortExtensionSize = sizeof(EHCI_EXTENSION);
3636     RegPacket.MiniPortEndpointSize = sizeof(EHCI_ENDPOINT);
3637     RegPacket.MiniPortTransferSize = sizeof(EHCI_TRANSFER);
3638     RegPacket.MiniPortResourcesSize = sizeof(EHCI_HC_RESOURCES);
3639 
3640     RegPacket.OpenEndpoint = EHCI_OpenEndpoint;
3641     RegPacket.ReopenEndpoint = EHCI_ReopenEndpoint;
3642     RegPacket.QueryEndpointRequirements = EHCI_QueryEndpointRequirements;
3643     RegPacket.CloseEndpoint = EHCI_CloseEndpoint;
3644     RegPacket.StartController = EHCI_StartController;
3645     RegPacket.StopController = EHCI_StopController;
3646     RegPacket.SuspendController = EHCI_SuspendController;
3647     RegPacket.ResumeController = EHCI_ResumeController;
3648     RegPacket.InterruptService = EHCI_InterruptService;
3649     RegPacket.InterruptDpc = EHCI_InterruptDpc;
3650     RegPacket.SubmitTransfer = EHCI_SubmitTransfer;
3651     RegPacket.SubmitIsoTransfer = EHCI_SubmitIsoTransfer;
3652     RegPacket.AbortTransfer = EHCI_AbortTransfer;
3653     RegPacket.GetEndpointState = EHCI_GetEndpointState;
3654     RegPacket.SetEndpointState = EHCI_SetEndpointState;
3655     RegPacket.PollEndpoint = EHCI_PollEndpoint;
3656     RegPacket.CheckController = EHCI_CheckController;
3657     RegPacket.Get32BitFrameNumber = EHCI_Get32BitFrameNumber;
3658     RegPacket.InterruptNextSOF = EHCI_InterruptNextSOF;
3659     RegPacket.EnableInterrupts = EHCI_EnableInterrupts;
3660     RegPacket.DisableInterrupts = EHCI_DisableInterrupts;
3661     RegPacket.PollController = EHCI_PollController;
3662     RegPacket.SetEndpointDataToggle = EHCI_SetEndpointDataToggle;
3663     RegPacket.GetEndpointStatus = EHCI_GetEndpointStatus;
3664     RegPacket.SetEndpointStatus = EHCI_SetEndpointStatus;
3665     RegPacket.RH_GetRootHubData = EHCI_RH_GetRootHubData;
3666     RegPacket.RH_GetStatus = EHCI_RH_GetStatus;
3667     RegPacket.RH_GetPortStatus = EHCI_RH_GetPortStatus;
3668     RegPacket.RH_GetHubStatus = EHCI_RH_GetHubStatus;
3669     RegPacket.RH_SetFeaturePortReset = EHCI_RH_SetFeaturePortReset;
3670     RegPacket.RH_SetFeaturePortPower = EHCI_RH_SetFeaturePortPower;
3671     RegPacket.RH_SetFeaturePortEnable = EHCI_RH_SetFeaturePortEnable;
3672     RegPacket.RH_SetFeaturePortSuspend = EHCI_RH_SetFeaturePortSuspend;
3673     RegPacket.RH_ClearFeaturePortEnable = EHCI_RH_ClearFeaturePortEnable;
3674     RegPacket.RH_ClearFeaturePortPower = EHCI_RH_ClearFeaturePortPower;
3675     RegPacket.RH_ClearFeaturePortSuspend = EHCI_RH_ClearFeaturePortSuspend;
3676     RegPacket.RH_ClearFeaturePortEnableChange = EHCI_RH_ClearFeaturePortEnableChange;
3677     RegPacket.RH_ClearFeaturePortConnectChange = EHCI_RH_ClearFeaturePortConnectChange;
3678     RegPacket.RH_ClearFeaturePortResetChange = EHCI_RH_ClearFeaturePortResetChange;
3679     RegPacket.RH_ClearFeaturePortSuspendChange = EHCI_RH_ClearFeaturePortSuspendChange;
3680     RegPacket.RH_ClearFeaturePortOvercurrentChange = EHCI_RH_ClearFeaturePortOvercurrentChange;
3681     RegPacket.RH_DisableIrq = EHCI_RH_DisableIrq;
3682     RegPacket.RH_EnableIrq = EHCI_RH_EnableIrq;
3683     RegPacket.StartSendOnePacket = EHCI_StartSendOnePacket;
3684     RegPacket.EndSendOnePacket = EHCI_EndSendOnePacket;
3685     RegPacket.PassThru = EHCI_PassThru;
3686     RegPacket.RebalanceEndpoint = EHCI_RebalanceEndpoint;
3687     RegPacket.FlushInterrupts = EHCI_FlushInterrupts;
3688     RegPacket.RH_ChirpRootPort = EHCI_RH_ChirpRootPort;
3689     RegPacket.TakePortControl = EHCI_TakePortControl;
3690 
3691     DriverObject->DriverUnload = EHCI_Unload;
3692 
3693     return USBPORT_RegisterUSBPortDriver(DriverObject,
3694                                          USB20_MINIPORT_INTERFACE_VERSION,
3695                                          &RegPacket);
3696 }
3697