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