xref: /reactos/drivers/usb/usbohci/usbohci.c (revision 019f21ee)
1 /*
2  * PROJECT:     ReactOS USB OHCI Miniport Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBOHCI main driver functions
5  * COPYRIGHT:   Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbohci.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define NDEBUG_OHCI_TRACE
14 #include "dbg_ohci.h"
15 
16 USBPORT_REGISTRATION_PACKET RegPacket;
17 
18 static const UCHAR Index[8] =
19 {
20     ENDPOINT_INTERRUPT_1ms - 1,
21     ENDPOINT_INTERRUPT_2ms - 1,
22     ENDPOINT_INTERRUPT_4ms - 1,
23     ENDPOINT_INTERRUPT_8ms - 1,
24     ENDPOINT_INTERRUPT_16ms - 1,
25     ENDPOINT_INTERRUPT_32ms - 1,
26     ENDPOINT_INTERRUPT_32ms - 1,
27     ENDPOINT_INTERRUPT_32ms - 1
28 };
29 
30 static const UCHAR Balance[OHCI_NUMBER_OF_INTERRUPTS] =
31 {
32     0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30,
33     1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31
34 };
35 
36 VOID
37 NTAPI
38 OHCI_DumpHcdED(POHCI_HCD_ED ED)
39 {
40     DPRINT("ED                - %p\n", ED);
41     DPRINT("EndpointControl   - %X\n", ED->HwED.EndpointControl.AsULONG);
42     DPRINT("TailPointer       - %08X\n", ED->HwED.TailPointer);
43     DPRINT("HeadPointer       - %08X\n", ED->HwED.HeadPointer);
44     DPRINT("NextED            - %08X\n", ED->HwED.NextED);
45 }
46 
47 VOID
48 NTAPI
49 OHCI_DumpHcdTD(POHCI_HCD_TD TD)
50 {
51     DPRINT("TD                - %p\n", TD);
52     DPRINT("gTD.Control       - %08X\n", TD->HwTD.gTD.Control.AsULONG);
53 if (TD->HwTD.gTD.CurrentBuffer)
54     DPRINT("gTD.CurrentBuffer - %08X\n", TD->HwTD.gTD.CurrentBuffer);
55 if (TD->HwTD.gTD.NextTD)
56     DPRINT("gTD.NextTD        - %08X\n", TD->HwTD.gTD.NextTD);
57 if (TD->HwTD.gTD.BufferEnd)
58     DPRINT("gTD.BufferEnd     - %08X\n", TD->HwTD.gTD.BufferEnd);
59 
60 if (TD->HwTD.SetupPacket.bmRequestType.B)
61     DPRINT("bmRequestType     - %02X\n", TD->HwTD.SetupPacket.bmRequestType.B);
62 if (TD->HwTD.SetupPacket.bRequest)
63     DPRINT("bRequest          - %02X\n", TD->HwTD.SetupPacket.bRequest);
64 if (TD->HwTD.SetupPacket.wValue.W)
65     DPRINT("wValue            - %04X\n", TD->HwTD.SetupPacket.wValue.W);
66 if (TD->HwTD.SetupPacket.wIndex.W)
67     DPRINT("wIndex            - %04X\n", TD->HwTD.SetupPacket.wIndex.W);
68 if (TD->HwTD.SetupPacket.wLength)
69     DPRINT("wLength           - %04X\n", TD->HwTD.SetupPacket.wLength);
70 
71     DPRINT("PhysicalAddress   - %p\n", TD->PhysicalAddress);
72     DPRINT("Flags             - %X\n", TD->Flags);
73     DPRINT("OhciTransfer      - %08X\n", TD->OhciTransfer);
74     DPRINT("NextTDVa          - %08X\n", TD->NextTDVa);
75 if (TD->TransferLen)
76     DPRINT("TransferLen       - %X\n", TD->TransferLen);
77 }
78 
79 VOID
80 NTAPI
81 OHCI_EnableList(IN POHCI_EXTENSION OhciExtension,
82                 IN POHCI_ENDPOINT OhciEndpoint)
83 {
84     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
85     PULONG CommandStatusReg;
86     ULONG TransferType;
87     OHCI_REG_COMMAND_STATUS CommandStatus;
88 
89     DPRINT_OHCI("OHCI_EnableList: ... \n");
90 
91     OperationalRegs = OhciExtension->OperationalRegs;
92     CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
93 
94     CommandStatus.AsULONG = 0;
95 
96     if (READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcControlHeadED))
97         CommandStatus.ControlListFilled = 1;
98 
99     if (READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcBulkHeadED))
100         CommandStatus.BulkListFilled = 1;
101 
102     TransferType = OhciEndpoint->EndpointProperties.TransferType;
103 
104     if (TransferType == USBPORT_TRANSFER_TYPE_BULK)
105         CommandStatus.BulkListFilled = 1;
106     else if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
107         CommandStatus.ControlListFilled = 1;
108 
109     WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
110 }
111 
112 VOID
113 NTAPI
114 OHCI_InsertEndpointInSchedule(IN POHCI_ENDPOINT OhciEndpoint)
115 {
116     POHCI_STATIC_ED HeadED;
117     POHCI_HCD_ED ED;
118     POHCI_HCD_ED PrevED;
119     PLIST_ENTRY HeadLink;
120 
121     DPRINT_OHCI("OHCI_InsertEndpointInSchedule: OhciEndpoint - %p\n",
122                 OhciEndpoint);
123 
124     ED = OhciEndpoint->HcdED;
125 
126     HeadED = OhciEndpoint->HeadED;
127     HeadLink = &HeadED->Link;
128 
129     if (IsListEmpty(HeadLink))
130     {
131         InsertHeadList(HeadLink, &ED->HcdEDLink);
132 
133         if (HeadED->Type == OHCI_STATIC_ED_TYPE_CONTROL ||
134             HeadED->Type == OHCI_STATIC_ED_TYPE_BULK)
135         {
136             ED->HwED.NextED = READ_REGISTER_ULONG(HeadED->pNextED);
137             WRITE_REGISTER_ULONG(HeadED->pNextED, ED->PhysicalAddress);
138         }
139         else if (HeadED->Type == OHCI_STATIC_ED_TYPE_INTERRUPT)
140         {
141             ED->HwED.NextED = *HeadED->pNextED;
142             *HeadED->pNextED = ED->PhysicalAddress;
143         }
144         else
145         {
146             DPRINT1("OHCI_InsertEndpointInSchedule: Unknown HeadED->Type - %x\n",
147                     HeadED->Type);
148             DbgBreakPoint();
149         }
150     }
151     else
152     {
153         PrevED = CONTAINING_RECORD(HeadLink->Blink,
154                                    OHCI_HCD_ED,
155                                    HcdEDLink);
156 
157         InsertTailList(HeadLink, &ED->HcdEDLink);
158 
159         ED->HwED.NextED = 0;
160         PrevED->HwED.NextED = ED->PhysicalAddress;
161     }
162 }
163 
164 POHCI_HCD_ED
165 NTAPI
166 OHCI_InitializeED(IN POHCI_ENDPOINT OhciEndpoint,
167                   IN POHCI_HCD_ED ED,
168                   IN POHCI_HCD_TD FirstTD,
169                   IN ULONG_PTR EdPA)
170 {
171     OHCI_ENDPOINT_CONTROL EndpointControl;
172     PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
173 
174     DPRINT_OHCI("OHCI_InitializeED: OhciEndpoint - %p, ED - %p, FirstTD - %p, EdPA - %p\n",
175                 OhciEndpoint,
176                 ED,
177                 FirstTD,
178                 EdPA);
179 
180     RtlZeroMemory(ED, sizeof(OHCI_HCD_ED));
181 
182     ED->PhysicalAddress = EdPA;
183 
184     EndpointProperties = &OhciEndpoint->EndpointProperties;
185 
186     EndpointControl = ED->HwED.EndpointControl;
187 
188     EndpointControl.FunctionAddress = EndpointProperties->DeviceAddress;
189     EndpointControl.EndpointNumber = EndpointProperties->EndpointAddress;
190     EndpointControl.MaximumPacketSize = EndpointProperties->TotalMaxPacketSize;
191 
192     if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
193     {
194         EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_FROM_TD;
195     }
196     else if (EndpointProperties->Direction)
197     {
198         EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_OUT;
199     }
200     else
201     {
202         EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_IN;
203     }
204 
205     if (EndpointProperties->DeviceSpeed == UsbLowSpeed)
206         EndpointControl.Speed = OHCI_ENDPOINT_LOW_SPEED;
207 
208     if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
209         EndpointControl.Format = OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
210     else
211         EndpointControl.sKip = 1;
212 
213     ED->HwED.EndpointControl = EndpointControl;
214 
215     ED->HwED.TailPointer = FirstTD->PhysicalAddress;
216     ED->HwED.HeadPointer = FirstTD->PhysicalAddress;
217 
218     FirstTD->Flags |= OHCI_HCD_TD_FLAG_ALLOCATED;
219 
220     OhciEndpoint->HcdTailP = FirstTD;
221     OhciEndpoint->HcdHeadP = FirstTD;
222 
223     return ED;
224 }
225 
226 VOID
227 NTAPI
228 OHCI_InitializeTDs(IN POHCI_ENDPOINT OhciEndpoint,
229                    IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties)
230 {
231     POHCI_HCD_TD TdVA;
232     ULONG TdPA;
233     ULONG TdCount;
234     ULONG ix;
235 
236     ASSERT(EndpointProperties->BufferLength > sizeof(OHCI_HCD_ED));
237 
238     TdCount = (EndpointProperties->BufferLength - sizeof(OHCI_HCD_ED)) /
239               sizeof(OHCI_HCD_TD);
240 
241     OhciEndpoint->MaxTransferDescriptors = TdCount;
242 
243     DPRINT_OHCI("OHCI_InitializeTDs: TdCount - %x\n", TdCount);
244 
245     ASSERT(TdCount > 0);
246 
247     TdVA = OhciEndpoint->FirstTD;
248 
249     TdPA = EndpointProperties->BufferPA + sizeof(OHCI_HCD_ED);
250 
251     for (ix = 0; ix < TdCount; ix++)
252     {
253         DPRINT_OHCI("OHCI_InitializeTDs: TdVA - %p, TdPA - %08X\n", TdVA, TdPA);
254 
255         RtlZeroMemory(TdVA, sizeof(OHCI_HCD_TD));
256 
257         TdVA->PhysicalAddress = TdPA;
258         TdVA->Flags = 0;
259         TdVA->OhciTransfer = 0;
260 
261         TdVA++;
262         TdPA += sizeof(OHCI_HCD_TD);
263     }
264 }
265 
266 MPSTATUS
267 NTAPI
268 OHCI_OpenControlEndpoint(IN POHCI_EXTENSION OhciExtension,
269                          IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
270                          IN POHCI_ENDPOINT OhciEndpoint)
271 {
272     POHCI_HCD_ED ED;
273 
274     DPRINT_OHCI("OHCI_OpenControlEndpoint: ... \n");
275 
276     ED = (POHCI_HCD_ED)EndpointProperties->BufferVA;
277 
278     OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED));
279     OhciEndpoint->HeadED = &OhciExtension->ControlStaticED;
280 
281     OHCI_InitializeTDs(OhciEndpoint, EndpointProperties);
282 
283     OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint,
284                                             ED,
285                                             OhciEndpoint->FirstTD,
286                                             EndpointProperties->BufferPA);
287 
288     OhciEndpoint->HcdED->Flags = OHCI_HCD_ED_FLAG_CONTROL |
289                                  OHCI_HCD_ED_FLAG_RESET_ON_HALT;
290 
291     OHCI_InsertEndpointInSchedule(OhciEndpoint);
292 
293     return MP_STATUS_SUCCESS;
294 }
295 
296 MPSTATUS
297 NTAPI
298 OHCI_OpenBulkEndpoint(IN POHCI_EXTENSION OhciExtension,
299                       IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
300                       IN POHCI_ENDPOINT OhciEndpoint)
301 {
302     POHCI_HCD_ED ED;
303 
304     DPRINT_OHCI("OHCI_OpenBulkEndpoint: ... \n");
305 
306     ED = (POHCI_HCD_ED)EndpointProperties->BufferVA;
307 
308     OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED));
309     OhciEndpoint->HeadED = &OhciExtension->BulkStaticED;
310 
311     OHCI_InitializeTDs(OhciEndpoint, EndpointProperties);
312 
313     OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint,
314                                             ED,
315                                             OhciEndpoint->FirstTD,
316                                             EndpointProperties->BufferPA);
317 
318     OHCI_InsertEndpointInSchedule(OhciEndpoint);
319 
320     return MP_STATUS_SUCCESS;
321 }
322 
323 MPSTATUS
324 NTAPI
325 OHCI_OpenInterruptEndpoint(IN POHCI_EXTENSION OhciExtension,
326                            IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
327                            IN POHCI_ENDPOINT OhciEndpoint)
328 {
329     UCHAR Period;
330     ULONG PeriodIdx = 0;
331     POHCI_HCD_ED ED;
332     ULONG ScheduleOffset;
333 
334     DPRINT_OHCI("OHCI_OpenInterruptEndpoint: ... \n");
335 
336     ED = (POHCI_HCD_ED)EndpointProperties->BufferVA;
337 
338     OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED));
339 
340     Period = EndpointProperties->Period;
341 
342     ASSERT(Period != 0);
343 
344     while (!(Period & 1))
345     {
346         PeriodIdx++;
347         Period >>= 1;
348     }
349 
350     ASSERT(PeriodIdx < ARRAYSIZE(Index));
351 
352     ScheduleOffset = EndpointProperties->ScheduleOffset;
353     DPRINT_OHCI("OHCI_OpenInterruptEndpoint: InitTD. Index[PeriodIdx] - %x, ScheduleOffset - %x\n",
354                 Index[PeriodIdx],
355                 ScheduleOffset);
356 
357     OhciEndpoint->HeadED = &OhciExtension->IntStaticED[Index[PeriodIdx] +
358                                                        ScheduleOffset];
359 
360     //OhciEndpoint->HeadED->UsbBandwidth += EndpointProperties->UsbBandwidth;
361 
362     OHCI_InitializeTDs(OhciEndpoint, EndpointProperties);
363 
364     OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint,
365                                             ED,
366                                             OhciEndpoint->FirstTD,
367                                             EndpointProperties->BufferPA);
368 
369     OHCI_InsertEndpointInSchedule(OhciEndpoint);
370 
371     return MP_STATUS_SUCCESS;
372 }
373 
374 MPSTATUS
375 NTAPI
376 OHCI_OpenIsoEndpoint(IN POHCI_EXTENSION OhciExtension,
377                      IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
378                      IN POHCI_ENDPOINT OhciEndpoint)
379 {
380     DPRINT1("OHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n");
381     return MP_STATUS_NOT_SUPPORTED;
382 }
383 
384 MPSTATUS
385 NTAPI
386 OHCI_OpenEndpoint(IN PVOID ohciExtension,
387                   IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
388                   IN PVOID ohciEndpoint)
389 {
390     POHCI_EXTENSION OhciExtension = ohciExtension;
391     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
392     ULONG TransferType;
393     MPSTATUS MPStatus;
394 
395     DPRINT_OHCI("OHCI_OpenEndpoint: ... \n");
396 
397     RtlCopyMemory(&OhciEndpoint->EndpointProperties,
398                   EndpointProperties,
399                   sizeof(OhciEndpoint->EndpointProperties));
400 
401     InitializeListHead(&OhciEndpoint->TDList);
402 
403     TransferType = EndpointProperties->TransferType;
404 
405     switch (TransferType)
406     {
407         case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
408             MPStatus = OHCI_OpenIsoEndpoint(OhciExtension,
409                                             EndpointProperties,
410                                             OhciEndpoint);
411             break;
412 
413         case USBPORT_TRANSFER_TYPE_CONTROL:
414             MPStatus = OHCI_OpenControlEndpoint(OhciExtension,
415                                                 EndpointProperties,
416                                                 OhciEndpoint);
417             break;
418 
419         case USBPORT_TRANSFER_TYPE_BULK:
420             MPStatus = OHCI_OpenBulkEndpoint(OhciExtension,
421                                              EndpointProperties,
422                                              OhciEndpoint);
423             break;
424 
425         case USBPORT_TRANSFER_TYPE_INTERRUPT:
426             MPStatus = OHCI_OpenInterruptEndpoint(OhciExtension,
427                                                   EndpointProperties,
428                                                   OhciEndpoint);
429             break;
430 
431         default:
432             MPStatus = MP_STATUS_NOT_SUPPORTED;
433             break;
434     }
435 
436     return MPStatus;
437 }
438 
439 MPSTATUS
440 NTAPI
441 OHCI_ReopenEndpoint(IN PVOID ohciExtension,
442                     IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
443                     IN PVOID ohciEndpoint)
444 {
445     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
446     POHCI_HCD_ED ED;
447 
448     DPRINT_OHCI("OHCI_ReopenEndpoint: ... \n");
449 
450     ED = OhciEndpoint->HcdED;
451 
452     RtlCopyMemory(&OhciEndpoint->EndpointProperties,
453                   EndpointProperties,
454                   sizeof(OhciEndpoint->EndpointProperties));
455 
456     ED->HwED.EndpointControl.FunctionAddress =
457         OhciEndpoint->EndpointProperties.DeviceAddress;
458 
459     ED->HwED.EndpointControl.MaximumPacketSize =
460         OhciEndpoint->EndpointProperties.TotalMaxPacketSize;
461 
462     return MP_STATUS_SUCCESS;
463 }
464 
465 VOID
466 NTAPI
467 OHCI_QueryEndpointRequirements(IN PVOID ohciExtension,
468                                IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
469                                IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements)
470 {
471     ULONG TransferType;
472 
473     DPRINT_OHCI("OHCI_QueryEndpointRequirements: ... \n");
474 
475     TransferType = EndpointProperties->TransferType;
476 
477     switch (TransferType)
478     {
479         case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
480             DPRINT_OHCI("OHCI_QueryEndpointRequirements: IsoTransfer\n");
481             EndpointRequirements->MaxTransferSize = OHCI_MAX_ISO_TRANSFER_SIZE;
482             EndpointRequirements->HeaderBufferSize =
483             sizeof(OHCI_HCD_ED) + OHCI_MAX_ISO_TD_COUNT * sizeof(OHCI_HCD_TD);
484             break;
485 
486         case USBPORT_TRANSFER_TYPE_CONTROL:
487             DPRINT_OHCI("OHCI_QueryEndpointRequirements: ControlTransfer\n");
488             EndpointRequirements->MaxTransferSize = OHCI_MAX_CONTROL_TRANSFER_SIZE;
489             EndpointRequirements->HeaderBufferSize =
490             sizeof(OHCI_HCD_ED) + OHCI_MAX_CONTROL_TD_COUNT * sizeof(OHCI_HCD_TD);
491             break;
492 
493         case USBPORT_TRANSFER_TYPE_BULK:
494             DPRINT_OHCI("OHCI_QueryEndpointRequirements: BulkTransfer\n");
495             EndpointRequirements->MaxTransferSize = OHCI_MAX_BULK_TRANSFER_SIZE;
496             EndpointRequirements->HeaderBufferSize =
497             sizeof(OHCI_HCD_ED) + OHCI_MAX_BULK_TD_COUNT * sizeof(OHCI_HCD_TD);
498             break;
499 
500         case USBPORT_TRANSFER_TYPE_INTERRUPT:
501             DPRINT_OHCI("OHCI_QueryEndpointRequirements: InterruptTransfer\n");
502             EndpointRequirements->MaxTransferSize = OHCI_MAX_INTERRUPT_TRANSFER_SIZE;
503             EndpointRequirements->HeaderBufferSize =
504             sizeof(OHCI_HCD_ED) + OHCI_MAX_INTERRUPT_TD_COUNT * sizeof(OHCI_HCD_TD);
505             break;
506 
507         default:
508             DPRINT1("OHCI_QueryEndpointRequirements: Unknown TransferType - %x\n",
509                     TransferType);
510             DbgBreakPoint();
511             break;
512     }
513 }
514 
515 VOID
516 NTAPI
517 OHCI_CloseEndpoint(IN PVOID ohciExtension,
518                    IN PVOID ohciEndpoint,
519                    IN BOOLEAN IsDoDisablePeriodic)
520 {
521 #if DBG
522     DPRINT1("OHCI_CloseEndpoint: Not supported\n");
523 #endif
524     return;
525 }
526 
527 MPSTATUS
528 NTAPI
529 OHCI_TakeControlHC(IN POHCI_EXTENSION OhciExtension,
530                    IN PUSBPORT_RESOURCES Resources)
531 {
532     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
533     PULONG ControlReg;
534     PULONG InterruptEnableReg;
535     PULONG InterruptDisableReg;
536     PULONG CommandStatusReg;
537     PULONG InterruptStatusReg;
538     OHCI_REG_CONTROL Control;
539     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
540     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
541     OHCI_REG_COMMAND_STATUS CommandStatus;
542     OHCI_REG_INTERRUPT_STATUS IntStatus;
543     LARGE_INTEGER StartTicks, CurrentTicks;
544     UINT32 TicksDiff;
545 
546     DPRINT("OHCI_TakeControlHC: ...\n");
547 
548     OperationalRegs = OhciExtension->OperationalRegs;
549 
550     ControlReg = (PULONG)&OperationalRegs->HcControl;
551     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
552     InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
553     CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
554     InterruptStatusReg = (PULONG)&OperationalRegs->HcInterruptStatus;
555 
556     /* 5.1.1.3 Take Control of Host Controller */
557     Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
558 
559     if (Control.InterruptRouting == 0)
560         return MP_STATUS_SUCCESS;
561 
562     DPRINT1("OHCI_TakeControlHC: detected Legacy BIOS\n");
563 
564     IntEnable.AsULONG = READ_REGISTER_ULONG(InterruptEnableReg);
565 
566     DPRINT("OHCI_TakeControlHC: Control - %lX, IntEnable - %lX\n",
567            Control.AsULONG,
568            IntEnable.AsULONG);
569 
570     if (Control.HostControllerFunctionalState == OHCI_HC_STATE_RESET &&
571         IntEnable.AsULONG == 0)
572     {
573         Control.AsULONG = 0;
574         WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
575         return MP_STATUS_SUCCESS;
576     }
577 
578     /* Enable interrupt generations */
579     IntEnable.AsULONG = 0;
580     IntEnable.MasterInterruptEnable = 1;
581 
582     WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
583 
584     /* Request a change of control of the HC */
585     CommandStatus.AsULONG = 0;
586     CommandStatus.OwnershipChangeRequest = 1;
587 
588     WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
589 
590     /* Disable interrupt generation due to Root Hub Status Change */
591     IntDisable.AsULONG = 0;
592     IntDisable.RootHubStatusChange = 1;
593 
594     WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
595 
596     /* Monitoring the InterruptRouting bit
597        to determine when the ownership change has taken effect. */
598 
599     TicksDiff = (500 * 10000) / KeQueryTimeIncrement(); // 500 ms
600     KeQueryTickCount(&StartTicks);
601 
602     do
603     {
604         Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
605 
606         if (Control.InterruptRouting == 0)
607         {
608             /* Clear all bits in register */
609             IntStatus.AsULONG = 0xFFFFFFFF;
610             WRITE_REGISTER_ULONG(InterruptStatusReg, IntStatus.AsULONG);
611 
612             /* Disable interrupt generations */
613             IntDisable.AsULONG = 0;
614             IntDisable.MasterInterruptEnable = 1;
615 
616             WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
617 
618             return MP_STATUS_SUCCESS;
619         }
620 
621         KeQueryTickCount(&CurrentTicks);
622     }
623     while (CurrentTicks.QuadPart - StartTicks.QuadPart < TicksDiff);
624 
625     return MP_STATUS_HW_ERROR;
626 }
627 
628 MPSTATUS
629 NTAPI
630 OHCI_StartController(IN PVOID ohciExtension,
631                      IN PUSBPORT_RESOURCES Resources)
632 {
633     POHCI_EXTENSION OhciExtension = ohciExtension;
634     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
635     PULONG CommandStatusReg;
636     PULONG FmIntervalReg;
637     PULONG ControlReg;
638     PULONG InterruptEnableReg;
639     PULONG RhStatusReg;
640     OHCI_REG_COMMAND_STATUS CommandStatus;
641     OHCI_REG_INTERRUPT_ENABLE_DISABLE Interrupts;
642     OHCI_REG_RH_STATUS RhStatus;
643     OHCI_REG_FRAME_INTERVAL FrameInterval;
644     ULONG MaxFrameIntervalAdjusting;
645     OHCI_REG_CONTROL Control;
646     UCHAR HeadIndex;
647     POHCI_ENDPOINT_DESCRIPTOR IntED;
648     ULONG_PTR IntEdPA;
649     POHCI_HCCA OhciHCCA;
650     LARGE_INTEGER StartTicks, CurrentTicks;
651     UINT32 TicksDiff;
652     ULONG ix;
653     ULONG jx;
654     MPSTATUS MPStatus = MP_STATUS_SUCCESS;
655 
656     DPRINT_OHCI("OHCI_StartController: ohciExtension - %p, Resources - %p\n",
657                 ohciExtension,
658                 Resources);
659 
660     /* HC on-chip operational registers */
661     OperationalRegs = (POHCI_OPERATIONAL_REGISTERS)Resources->ResourceBase;
662     OhciExtension->OperationalRegs = OperationalRegs;
663 
664     CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
665     FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
666     ControlReg = (PULONG)&OperationalRegs->HcControl;
667     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
668     RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
669 
670     /* 5.1.1 Initialization */
671 
672     MPStatus = OHCI_TakeControlHC(OhciExtension, Resources);
673 
674     if (MPStatus != MP_STATUS_SUCCESS)
675     {
676         DPRINT1("OHCI_StartController: OHCI_TakeControlHC return MPStatus - %x\n",
677                 MPStatus);
678 
679         return MPStatus;
680     }
681 
682     OhciExtension->HcResourcesVA = (POHCI_HC_RESOURCES)Resources->StartVA;
683     OhciExtension->HcResourcesPA = Resources->StartPA;
684 
685     DPRINT_OHCI("OHCI_StartController: HcResourcesVA - %p, HcResourcesPA - %lx\n",
686                 OhciExtension->HcResourcesVA,
687                 OhciExtension->HcResourcesPA);
688 
689     /* 5.2.7.2 Interrupt */
690 
691     /* Build structure of interrupt static EDs */
692     for (ix = 0; ix < INTERRUPT_ENDPOINTs; ix++)
693     {
694         IntED = &OhciExtension->HcResourcesVA->InterrruptHeadED[ix];
695         IntEdPA = OhciExtension->HcResourcesPA + FIELD_OFFSET(OHCI_HC_RESOURCES, InterrruptHeadED[ix]);
696 
697         if (ix == (ENDPOINT_INTERRUPT_1ms - 1))
698         {
699             HeadIndex = ED_EOF;
700             IntED->NextED = 0;
701         }
702         else
703         {
704             HeadIndex = ((ix - 1) / 2);
705 
706             ASSERT(HeadIndex >= (ENDPOINT_INTERRUPT_1ms - 1) &&
707                    HeadIndex < (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms));
708 
709             IntED->NextED = OhciExtension->IntStaticED[HeadIndex].PhysicalAddress;
710         }
711 
712         IntED->EndpointControl.sKip = 1;
713 
714         IntED->TailPointer = 0;
715         IntED->HeadPointer = 0;
716 
717         OhciExtension->IntStaticED[ix].HwED = IntED;
718         OhciExtension->IntStaticED[ix].PhysicalAddress = IntEdPA;
719         OhciExtension->IntStaticED[ix].HeadIndex = HeadIndex;
720         OhciExtension->IntStaticED[ix].pNextED = &IntED->NextED;
721         OhciExtension->IntStaticED[ix].Type = OHCI_STATIC_ED_TYPE_INTERRUPT;
722 
723         InitializeListHead(&OhciExtension->IntStaticED[ix].Link);
724     }
725 
726     OhciHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
727     DPRINT_OHCI("OHCI_InitializeSchedule: OhciHCCA - %p\n", OhciHCCA);
728 
729     /* Set head pointers which start from HCCA */
730     for (ix = 0, jx = (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms);
731          ix < OHCI_NUMBER_OF_INTERRUPTS;
732          ix++, jx++)
733     {
734         OhciHCCA->InterrruptTable[Balance[ix]] =
735             OhciExtension->IntStaticED[jx].PhysicalAddress;
736 
737         OhciExtension->IntStaticED[jx].pNextED =
738             (PULONG)&OhciHCCA->InterrruptTable[Balance[ix]];
739 
740         OhciExtension->IntStaticED[jx].HccaIndex = Balance[ix];
741     }
742 
743     DPRINT_OHCI("OHCI_InitializeSchedule: ix - %x\n", ix);
744 
745     /* Init static Control and Bulk EDs head pointers which start from HCCA */
746     InitializeListHead(&OhciExtension->ControlStaticED.Link);
747 
748     OhciExtension->ControlStaticED.HeadIndex = ED_EOF;
749     OhciExtension->ControlStaticED.Type = OHCI_STATIC_ED_TYPE_CONTROL;
750     OhciExtension->ControlStaticED.pNextED = &OperationalRegs->HcControlHeadED;
751 
752     InitializeListHead(&OhciExtension->BulkStaticED.Link);
753 
754     OhciExtension->BulkStaticED.HeadIndex = ED_EOF;
755     OhciExtension->BulkStaticED.Type = OHCI_STATIC_ED_TYPE_BULK;
756     OhciExtension->BulkStaticED.pNextED = &OperationalRegs->HcBulkHeadED;
757 
758     /* 6.3.1 Frame Timing */
759     FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
760 
761     MaxFrameIntervalAdjusting = OHCI_DEFAULT_FRAME_INTERVAL / 10; // 10%
762 
763     if ((FrameInterval.FrameInterval) < (OHCI_DEFAULT_FRAME_INTERVAL - MaxFrameIntervalAdjusting) ||
764         (FrameInterval.FrameInterval) > (OHCI_DEFAULT_FRAME_INTERVAL + MaxFrameIntervalAdjusting))
765     {
766         FrameInterval.FrameInterval = OHCI_DEFAULT_FRAME_INTERVAL;
767     }
768 
769     /* 5.4 FrameInterval Counter */
770     FrameInterval.FrameIntervalToggle = 1;
771 
772     /* OHCI_MAXIMUM_OVERHEAD is the maximum overhead per frame */
773     FrameInterval.FSLargestDataPacket =
774         ((FrameInterval.FrameInterval - OHCI_MAXIMUM_OVERHEAD) * 6) / 7;
775 
776     OhciExtension->FrameInterval = FrameInterval;
777 
778     DPRINT_OHCI("OHCI_StartController: FrameInterval - %lX\n",
779                 FrameInterval.AsULONG);
780 
781     /* Reset HostController */
782     CommandStatus.AsULONG = 0;
783     CommandStatus.HostControllerReset = 1;
784 
785     WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
786 
787     KeStallExecutionProcessor(25);
788 
789     Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
790     Control.HostControllerFunctionalState = OHCI_HC_STATE_RESET;
791 
792     WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
793 
794     TicksDiff = (500 * 10000) / KeQueryTimeIncrement(); // 500 ms
795     KeQueryTickCount(&StartTicks);
796 
797     while (TRUE)
798     {
799         WRITE_REGISTER_ULONG(FmIntervalReg, OhciExtension->FrameInterval.AsULONG);
800         FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
801 
802         KeQueryTickCount(&CurrentTicks);
803 
804         if (CurrentTicks.QuadPart - StartTicks.QuadPart >= TicksDiff)
805         {
806             MPStatus = MP_STATUS_HW_ERROR;
807             break;
808         }
809 
810         if (FrameInterval.AsULONG == OhciExtension->FrameInterval.AsULONG)
811         {
812             MPStatus = MP_STATUS_SUCCESS;
813             break;
814         }
815     }
816 
817     if (MPStatus != MP_STATUS_SUCCESS)
818     {
819         DPRINT_OHCI("OHCI_StartController: frame interval not set\n");
820         return MPStatus;
821     }
822 
823     /* Setup HcPeriodicStart register */
824     WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart,
825                         (OhciExtension->FrameInterval.FrameInterval * 9) / 10); //90%
826 
827     /* Setup HcHCCA register */
828     WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA,
829                          OhciExtension->HcResourcesPA + FIELD_OFFSET(OHCI_HC_RESOURCES, HcHCCA));
830 
831     /* Setup HcInterruptEnable register */
832     Interrupts.AsULONG = 0;
833 
834     Interrupts.SchedulingOverrun = 1;
835     Interrupts.WritebackDoneHead = 1;
836     Interrupts.UnrecoverableError = 1;
837     Interrupts.FrameNumberOverflow = 1;
838     Interrupts.OwnershipChange = 1;
839 
840     WRITE_REGISTER_ULONG(InterruptEnableReg, Interrupts.AsULONG);
841 
842     /* Setup HcControl register */
843     Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
844 
845     Control.ControlBulkServiceRatio = 0; // FIXME (1 : 1)
846     Control.PeriodicListEnable = 1;
847     Control.IsochronousEnable = 1;
848     Control.ControlListEnable = 1;
849     Control.BulkListEnable = 1;
850     Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
851 
852     WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
853 
854     /* Setup HcRhStatus register */
855     RhStatus.AsULONG = 0;
856     RhStatus.SetGlobalPower = 1;
857 
858     WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
859 
860     return MP_STATUS_SUCCESS;
861 }
862 
863 VOID
864 NTAPI
865 OHCI_StopController(IN PVOID ohciExtension,
866                     IN BOOLEAN IsDoDisableInterrupts)
867 {
868     POHCI_EXTENSION OhciExtension = ohciExtension;
869     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
870     PULONG ControlReg;
871     PULONG InterruptDisableReg;
872     PULONG InterruptStatusReg;
873     OHCI_REG_CONTROL Control;
874     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
875     OHCI_REG_INTERRUPT_STATUS IntStatus;
876 
877     DPRINT("OHCI_StopController: ... \n");
878 
879     OperationalRegs = OhciExtension->OperationalRegs;
880 
881     ControlReg = (PULONG)&OperationalRegs->HcControl;
882     InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
883     InterruptStatusReg = (PULONG)&OperationalRegs->HcInterruptStatus;
884 
885     /* Setup HcControl register */
886     Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
887 
888     Control.PeriodicListEnable = 0;
889     Control.IsochronousEnable = 0;
890     Control.ControlListEnable = 0;
891     Control.BulkListEnable = 0;
892     Control.HostControllerFunctionalState = OHCI_HC_STATE_SUSPEND;
893     Control.RemoteWakeupEnable = 0;
894 
895     WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
896 
897     /* Disable interrupt generations */
898     IntDisable.AsULONG = 0xFFFFFFFF;
899     WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
900 
901     /* Clear all bits in HcInterruptStatus register */
902     IntStatus.AsULONG = 0xFFFFFFFF;
903     WRITE_REGISTER_ULONG(InterruptStatusReg, IntStatus.AsULONG);
904 }
905 
906 VOID
907 NTAPI
908 OHCI_SuspendController(IN PVOID ohciExtension)
909 {
910     POHCI_EXTENSION OhciExtension = ohciExtension;
911     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
912     PULONG ControlReg;
913     PULONG InterruptEnableReg;
914     OHCI_REG_CONTROL Control;
915     OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptReg;
916 
917     DPRINT("OHCI_SuspendController: ... \n");
918 
919     OperationalRegs = OhciExtension->OperationalRegs;
920     ControlReg = (PULONG)&OperationalRegs->HcControl;
921     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
922 
923     /* Disable all interrupt generations */
924     WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptDisable.AsULONG,
925                          0xFFFFFFFF);
926 
927     /* Clear all bits in HcInterruptStatus register */
928     WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG,
929                          0xFFFFFFFF);
930 
931     /* Setup HcControl register */
932     Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
933     Control.HostControllerFunctionalState = OHCI_HC_STATE_SUSPEND;
934     Control.RemoteWakeupEnable =  1;
935 
936     WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
937 
938     /* Setup HcInterruptEnable register */
939     InterruptReg.AsULONG = 0;
940     InterruptReg.ResumeDetected = 1;
941     InterruptReg.UnrecoverableError = 1;
942     InterruptReg.RootHubStatusChange = 1;
943     InterruptReg.MasterInterruptEnable = 1;
944 
945     WRITE_REGISTER_ULONG(InterruptEnableReg, InterruptReg.AsULONG);
946 }
947 
948 MPSTATUS
949 NTAPI
950 OHCI_ResumeController(IN PVOID ohciExtension)
951 {
952     POHCI_EXTENSION OhciExtension = ohciExtension;
953     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
954     PULONG ControlReg;
955     PULONG InterruptEnableReg;
956     POHCI_HCCA HcHCCA;
957     OHCI_REG_CONTROL control;
958     OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptReg;
959 
960     DPRINT("OHCI_ResumeController \n");
961 
962     OperationalRegs = OhciExtension->OperationalRegs;
963     ControlReg = (PULONG)&OperationalRegs->HcControl;
964     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
965 
966     control.AsULONG = READ_REGISTER_ULONG(ControlReg);
967 
968     if (control.HostControllerFunctionalState != OHCI_HC_STATE_SUSPEND)
969         return MP_STATUS_HW_ERROR;
970 
971     HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
972     HcHCCA->Pad1 = 0;
973 
974     /* Setup HcControl register */
975     control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
976     WRITE_REGISTER_ULONG(ControlReg, control.AsULONG);
977 
978     /* Setup HcInterruptEnable register */
979     InterruptReg.AsULONG = 0;
980     InterruptReg.SchedulingOverrun = 1;
981     InterruptReg.WritebackDoneHead = 1;
982     InterruptReg.UnrecoverableError = 1;
983     InterruptReg.FrameNumberOverflow = 1;
984     InterruptReg.OwnershipChange = 1;
985 
986     WRITE_REGISTER_ULONG(InterruptEnableReg, InterruptReg.AsULONG);
987     WRITE_REGISTER_ULONG(ControlReg, control.AsULONG);
988 
989     return MP_STATUS_SUCCESS;
990 }
991 
992 BOOLEAN
993 NTAPI
994 OHCI_HardwarePresent(IN POHCI_EXTENSION OhciExtension,
995                      IN BOOLEAN IsInvalidateController)
996 {
997     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
998     PULONG CommandStatusReg;
999 
1000     OperationalRegs = OhciExtension->OperationalRegs;
1001     CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
1002 
1003     if (READ_REGISTER_ULONG(CommandStatusReg) != 0xFFFFFFFF)
1004         return TRUE;
1005 
1006     DPRINT1("OHCI_HardwarePresent: IsInvalidateController - %x\n",
1007             IsInvalidateController);
1008 
1009     if (IsInvalidateController)
1010     {
1011         RegPacket.UsbPortInvalidateController(OhciExtension,
1012                                               USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE);
1013     }
1014 
1015     return FALSE;
1016 }
1017 
1018 BOOLEAN
1019 NTAPI
1020 OHCI_InterruptService(IN PVOID ohciExtension)
1021 {
1022     POHCI_EXTENSION OhciExtension = ohciExtension;
1023     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
1024     OHCI_REG_INTERRUPT_STATUS IntStatus;
1025     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
1026     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
1027     BOOLEAN HardwarePresent = FALSE;
1028 
1029     DPRINT_OHCI("OHCI_Interrupt: Ext %p\n", OhciExtension);
1030 
1031     OperationalRegs = OhciExtension->OperationalRegs;
1032 
1033     HardwarePresent = OHCI_HardwarePresent(OhciExtension, FALSE);
1034 
1035     if (!HardwarePresent)
1036         return FALSE;
1037 
1038     IntEnable.AsULONG = READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcInterruptEnable);
1039     IntStatus.AsULONG = READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcInterruptStatus) & IntEnable.AsULONG;
1040 
1041     if ((IntStatus.AsULONG == 0) || (IntEnable.MasterInterruptEnable == 0))
1042         return FALSE;
1043 
1044     if (IntStatus.UnrecoverableError)
1045         DPRINT1("OHCI_InterruptService: IntStatus.UnrecoverableError\n");
1046 
1047     if (IntStatus.FrameNumberOverflow)
1048     {
1049         POHCI_HCCA HcHCCA;
1050         ULONG fm;
1051         ULONG hp;
1052 
1053         HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
1054 
1055         DPRINT("FrameNumberOverflow %lX\n", HcHCCA->FrameNumber);
1056 
1057         hp = OhciExtension->FrameHighPart;
1058         fm = HcHCCA->FrameNumber;
1059 
1060         /* Increment value of FrameHighPart */
1061         OhciExtension->FrameHighPart += 1 * (1 << 16) - ((hp ^ fm) & 0x8000);
1062     }
1063 
1064     /* Disable interrupt generation */
1065     IntDisable.AsULONG = 0;
1066     IntDisable.MasterInterruptEnable = 1;
1067     WRITE_REGISTER_ULONG((PULONG)&OperationalRegs->HcInterruptDisable,
1068                          IntDisable.AsULONG);
1069 
1070     return TRUE;
1071 }
1072 
1073 VOID
1074 NTAPI
1075 OHCI_InterruptDpc(IN PVOID ohciExtension,
1076                   IN BOOLEAN IsDoEnableInterrupts)
1077 {
1078     POHCI_EXTENSION OhciExtension = ohciExtension;
1079     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
1080     PULONG InterruptDisableReg;
1081     PULONG InterruptEnableReg;
1082     PULONG InterruptStatusReg;
1083     OHCI_REG_INTERRUPT_STATUS IntStatus;
1084     OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptBits;
1085     POHCI_HCCA HcHCCA;
1086 
1087     OperationalRegs = OhciExtension->OperationalRegs;
1088 
1089     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
1090     InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
1091     InterruptStatusReg = (PULONG)&OperationalRegs->HcInterruptStatus;
1092 
1093     DPRINT_OHCI("OHCI_InterruptDpc: OhciExtension - %p, IsDoEnableInterrupts - %x\n",
1094                 OhciExtension,
1095                 IsDoEnableInterrupts);
1096 
1097     IntStatus.AsULONG = READ_REGISTER_ULONG(InterruptStatusReg);
1098 
1099     if (IntStatus.RootHubStatusChange)
1100     {
1101         DPRINT_OHCI("OHCI_InterruptDpc: RootHubStatusChange\n");
1102         RegPacket.UsbPortInvalidateRootHub(OhciExtension);
1103     }
1104 
1105     if (IntStatus.WritebackDoneHead)
1106     {
1107         DPRINT_OHCI("OHCI_InterruptDpc: WritebackDoneHead\n");
1108 
1109         HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
1110         HcHCCA->DoneHead = 0;
1111 
1112         RegPacket.UsbPortInvalidateEndpoint(OhciExtension, NULL);
1113     }
1114 
1115     if (IntStatus.StartofFrame)
1116     {
1117         /* Disable interrupt generation due to Start of Frame */
1118         InterruptBits.AsULONG = 0;
1119         InterruptBits.StartofFrame = 1;
1120 
1121         WRITE_REGISTER_ULONG(InterruptDisableReg, InterruptBits.AsULONG);
1122     }
1123 
1124     if (IntStatus.ResumeDetected)
1125         DPRINT1("OHCI_IntDpc: ResumeDetected\n");
1126 
1127     if (IntStatus.UnrecoverableError)
1128     {
1129         DPRINT1("OHCI_IntDpc: UnrecoverableError\n");
1130     }
1131 
1132     WRITE_REGISTER_ULONG(InterruptStatusReg, IntStatus.AsULONG);
1133 
1134     if (IsDoEnableInterrupts)
1135     {
1136         /*  Enable interrupt generation */
1137         InterruptBits.AsULONG = 0;
1138         InterruptBits.MasterInterruptEnable = 1;
1139 
1140         WRITE_REGISTER_ULONG(InterruptEnableReg, InterruptBits.AsULONG);
1141     }
1142 }
1143 
1144 /**
1145  * @brief      Forms the next General Transfer Descriptor for the current transfer
1146  *
1147  * @param[in]  OhciExtension  The ohci extension
1148  * @param[in]  TransferedLen  The consolidated length of all previous descriptors' buffers
1149  * @param[in]  OhciTransfer   The ohci transfer
1150  * @param[out] TD             The transfer descriptor we are forming
1151  * @param[in]  SGList         The scatter/gather list
1152  *
1153  * @return     The length of all previous buffers summed with the length of the current buffer
1154  */
1155 static
1156 ULONG
1157 OHCI_MapTransferToTD(IN POHCI_EXTENSION OhciExtension,
1158                      IN ULONG TransferedLen,
1159                      IN POHCI_TRANSFER OhciTransfer,
1160                      OUT POHCI_HCD_TD TD,
1161                      IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1162 {
1163     PUSBPORT_SCATTER_GATHER_ELEMENT SgElement;
1164     ULONG SgIdx, CurrentTransferLen, BufferEnd, CurrentBuffer;
1165     ULONG TransferDataLeft = OhciTransfer->TransferParameters->TransferBufferLength - TransferedLen;
1166 
1167     DPRINT_OHCI("OHCI_MapTransferToTD: TransferedLen - %x\n", TransferedLen);
1168 
1169     for (SgIdx = 0; SgIdx < SGList->SgElementCount; SgIdx++)
1170     {
1171         SgElement = &SGList->SgElement[SgIdx];
1172 
1173         if (TransferedLen >= SgElement->SgOffset &&
1174             TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength)
1175         {
1176             break;
1177         }
1178     }
1179 
1180     DPRINT_OHCI("OHCI_MapTransferToTD: SgIdx - %x, SgCount - %x\n",
1181                 SgIdx,
1182                 SGList->SgElementCount);
1183 
1184     ASSERT(SgIdx < SGList->SgElementCount);
1185     ASSERT(TransferedLen == SgElement->SgOffset);
1186 
1187     /* The buffer for a TD can be 0 to 8192 bytes long,
1188      * and can span within mo more than two 4k pages (see OpenHCI spec 3.3.2)
1189      * CurrentBuffer - the (physical) address of the first byte in the buffer
1190      * BufferEnd - the address of the last byte in the buffer. It can be on a different physical 4k page
1191      * when a controller will reach the end of a page from CurrentBuffer, it will take the first 20 bits
1192      * of the BufferEnd as a next address (OpenHCI spec, 4.3.1.3.1)
1193      */
1194 
1195     CurrentBuffer = SgElement->SgPhysicalAddress.LowPart;
1196 
1197     if (TransferDataLeft <= SgElement->SgTransferLength)
1198     {
1199         CurrentTransferLen = TransferDataLeft;
1200         BufferEnd = SgElement->SgPhysicalAddress.LowPart + CurrentTransferLen - 1;
1201     }
1202     else
1203     {
1204         PUSBPORT_SCATTER_GATHER_ELEMENT SgNextElement;
1205         ASSERT(SGList->SgElementCount - SgIdx > 1);
1206 
1207         SgNextElement = &SGList->SgElement[SgIdx + 1];
1208 
1209         TransferDataLeft -= SgElement->SgTransferLength;
1210         CurrentTransferLen = SgElement->SgTransferLength;
1211 
1212         if (TransferDataLeft <= SgNextElement->SgTransferLength)
1213         {
1214             CurrentTransferLen += TransferDataLeft;
1215             BufferEnd = SgNextElement->SgPhysicalAddress.LowPart + TransferDataLeft - 1;
1216         }
1217         else
1218         {
1219             CurrentTransferLen += SgNextElement->SgTransferLength;
1220             BufferEnd = SgNextElement->SgPhysicalAddress.LowPart + SgNextElement->SgTransferLength - 1;
1221         }
1222     }
1223 
1224     TD->HwTD.gTD.CurrentBuffer = CurrentBuffer;
1225     TD->HwTD.gTD.BufferEnd = BufferEnd;
1226     TD->TransferLen = CurrentTransferLen;
1227 
1228     return TransferedLen + CurrentTransferLen;
1229 }
1230 
1231 POHCI_HCD_TD
1232 NTAPI
1233 OHCI_AllocateTD(IN POHCI_EXTENSION OhciExtension,
1234                 IN POHCI_ENDPOINT OhciEndpoint)
1235 {
1236     POHCI_HCD_TD TD;
1237 
1238     DPRINT_OHCI("OHCI_AllocateTD: ... \n");
1239 
1240     TD = OhciEndpoint->FirstTD;
1241 
1242     while (TD->Flags & OHCI_HCD_TD_FLAG_ALLOCATED)
1243     {
1244         TD += 1;
1245     }
1246 
1247     TD->Flags |= OHCI_HCD_TD_FLAG_ALLOCATED;
1248 
1249     RtlSecureZeroMemory(&TD->HwTD, sizeof(TD->HwTD));
1250 
1251     return TD;
1252 }
1253 
1254 ULONG
1255 NTAPI
1256 OHCI_RemainTDs(IN POHCI_EXTENSION OhciExtension,
1257                IN POHCI_ENDPOINT OhciEndpoint)
1258 {
1259     POHCI_HCD_TD TD;
1260     ULONG MaxTDs;
1261     ULONG RemainTDs;
1262     ULONG ix;
1263 
1264     DPRINT_OHCI("OHCI_RemainTDs: ... \n");
1265 
1266     MaxTDs = OhciEndpoint->MaxTransferDescriptors;
1267     TD = OhciEndpoint->FirstTD;
1268 
1269     RemainTDs = 0;
1270 
1271     for (ix = 0; ix < MaxTDs; ix++)
1272     {
1273         if (!(TD->Flags & OHCI_HCD_TD_FLAG_ALLOCATED))
1274             RemainTDs++;
1275 
1276         TD += 1;
1277     }
1278 
1279     return RemainTDs;
1280 }
1281 
1282 static
1283 MPSTATUS
1284 OHCI_ControlTransfer(IN POHCI_EXTENSION OhciExtension,
1285                      IN POHCI_ENDPOINT OhciEndpoint,
1286                      IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1287                      IN POHCI_TRANSFER OhciTransfer,
1288                      IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1289 {
1290     POHCI_HCD_TD SetupTD;
1291     POHCI_HCD_TD TD;
1292     POHCI_HCD_TD PrevTD;
1293     ULONG MaxTDs;
1294     ULONG TransferedLen;
1295     UCHAR DataToggle;
1296 
1297     DPRINT_OHCI("OHCI_ControlTransfer: Ext %p, Endpoint %p\n",
1298                 OhciExtension,
1299                 OhciEndpoint);
1300 
1301     MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint);
1302 
1303     if ((SGList->SgElementCount + OHCI_NON_DATA_CONTROL_TDS) > MaxTDs)
1304         return MP_STATUS_FAILURE;
1305 
1306     /* Form a setup packet first */
1307     SetupTD = OhciEndpoint->HcdTailP;
1308     RtlSecureZeroMemory(&SetupTD->HwTD, sizeof(SetupTD->HwTD));
1309 
1310     SetupTD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1311     SetupTD->OhciTransfer = OhciTransfer;
1312 
1313     OhciTransfer->PendingTDs++;
1314 
1315     RtlCopyMemory(&SetupTD->HwTD.SetupPacket,
1316                   &TransferParameters->SetupPacket,
1317                   sizeof(SetupTD->HwTD.SetupPacket));
1318 
1319     SetupTD->HwTD.gTD.CurrentBuffer = SetupTD->PhysicalAddress + FIELD_OFFSET(OHCI_HCD_TD, HwTD.SetupPacket);
1320     SetupTD->HwTD.gTD.BufferEnd = SetupTD->PhysicalAddress + FIELD_OFFSET(OHCI_HCD_TD, HwTD.SetupPacket) +
1321                                   sizeof(USB_DEFAULT_PIPE_SETUP_PACKET) - 1;
1322     SetupTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1323     SetupTD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1324     SetupTD->HwTD.gTD.Control.DataToggle = OHCI_TD_DATA_TOGGLE_DATA0;
1325 
1326     PrevTD = SetupTD;
1327 
1328     /* Data packets follow a setup packet (if any) */
1329     TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1330     TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1331     TD->OhciTransfer = OhciTransfer;
1332 
1333     PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1334     PrevTD->NextTDVa = TD;
1335 
1336     /* The first data packet should use DATA1, subsequent ones use DATA0 (OpenHCI spec, 4.3.1.3.4) */
1337     DataToggle = OHCI_TD_DATA_TOGGLE_DATA1;
1338     TransferedLen = 0;
1339 
1340     while (TransferedLen < TransferParameters->TransferBufferLength)
1341     {
1342         OhciTransfer->PendingTDs++;
1343 
1344         if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
1345             TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1346         else
1347             TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1348 
1349         TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1350         TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1351         TD->HwTD.gTD.Control.DataToggle = DataToggle;
1352 
1353         TransferedLen = OHCI_MapTransferToTD(OhciExtension,
1354                                              TransferedLen,
1355                                              OhciTransfer,
1356                                              TD,
1357                                              SGList);
1358 
1359         PrevTD = TD;
1360 
1361         TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1362         TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1363         TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1364         TD->OhciTransfer = OhciTransfer;
1365 
1366         PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1367         PrevTD->NextTDVa = TD;
1368 
1369         DataToggle = OHCI_TD_DATA_TOGGLE_DATA0;
1370     }
1371 
1372     if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK)
1373     {
1374         PrevTD->HwTD.gTD.Control.BufferRounding = TRUE;
1375         OhciTransfer->Flags |= OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK;
1376     }
1377 
1378     /* After data packets, goes a status packet */
1379 
1380     TD->Flags |= OHCI_HCD_TD_FLAG_CONTROL_STATUS;
1381     TD->TransferLen = 0;
1382 
1383     if ((TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) != 0)
1384     {
1385         TD->HwTD.gTD.Control.BufferRounding = FALSE;
1386         TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1387     }
1388     else
1389     {
1390         TD->HwTD.gTD.Control.BufferRounding = TRUE;
1391         TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1392     }
1393 
1394     /* OpenHCI spec, 4.3.1.3.4 */
1395     TD->HwTD.gTD.Control.DataToggle = OHCI_TD_DATA_TOGGLE_DATA1;
1396     TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1397     TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_IMMEDIATE;
1398 
1399     OhciTransfer->PendingTDs++;
1400     OhciTransfer->ControlStatusTD = TD;
1401 
1402     PrevTD = TD;
1403 
1404     /* And the last descriptor, which is not used in the current transfer (OpenHCI spec, 4.6) */
1405     TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1406 
1407     PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1408     PrevTD->NextTDVa = TD;
1409 
1410     TD->NextTDVa = NULL;
1411     /* TD->HwTD.gTD.NextTD = 0; */
1412 
1413     OhciTransfer->NextTD = TD;
1414     OhciEndpoint->HcdTailP = TD;
1415 
1416     OhciEndpoint->HcdED->HwED.TailPointer = TD->PhysicalAddress;
1417 
1418     OHCI_EnableList(OhciExtension, OhciEndpoint);
1419 
1420     return MP_STATUS_SUCCESS;
1421 }
1422 
1423 static
1424 MPSTATUS
1425 OHCI_BulkOrInterruptTransfer(IN POHCI_EXTENSION OhciExtension,
1426                              IN POHCI_ENDPOINT OhciEndpoint,
1427                              IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1428                              IN POHCI_TRANSFER OhciTransfer,
1429                              IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1430 {
1431     POHCI_HCD_TD TD;
1432     POHCI_HCD_TD PrevTD;
1433     ULONG TransferedLen;
1434     ULONG MaxTDs;
1435 
1436     DPRINT_OHCI("OHCI_BulkOrInterruptTransfer: ... \n");
1437 
1438     MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint);
1439 
1440     if (SGList->SgElementCount > MaxTDs)
1441         return MP_STATUS_FAILURE;
1442 
1443     TD = OhciEndpoint->HcdTailP;
1444 
1445     TransferedLen = 0;
1446 
1447     do
1448     {
1449         TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1450         TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1451 
1452         if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
1453         {
1454             TD->HwTD.gTD.Control.BufferRounding = FALSE;
1455             TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1456         }
1457         else
1458         {
1459             TD->HwTD.gTD.Control.BufferRounding = TRUE;
1460             TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1461         }
1462 
1463         TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1464         TD->OhciTransfer = OhciTransfer;
1465 
1466         if (TransferParameters->TransferBufferLength)
1467         {
1468             TransferedLen = OHCI_MapTransferToTD(OhciExtension,
1469                                                  TransferedLen,
1470                                                  OhciTransfer,
1471                                                  TD,
1472                                                  SGList);
1473         }
1474         else
1475         {
1476             ASSERT(SGList->SgElementCount == 0);
1477             TD->TransferLen = 0;
1478         }
1479 
1480         PrevTD = TD;
1481 
1482         TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1483         OhciTransfer->PendingTDs++;
1484 
1485         PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1486         PrevTD->NextTDVa = TD;
1487     }
1488     while (TransferedLen < TransferParameters->TransferBufferLength);
1489 
1490     if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK)
1491     {
1492         PrevTD->HwTD.gTD.Control.BufferRounding = TRUE;
1493         OhciTransfer->Flags |= OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK;
1494     }
1495 
1496     PrevTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_IMMEDIATE;
1497 
1498     /* The last TD in a chain is not used in a transfer. The controller does not access it
1499      * so it will be used for chaining a next transfer to it (OpenHCI spec, 4.6)
1500      */
1501     /* TD->HwTD.gTD.NextTD = 0; */
1502     TD->NextTDVa = NULL;
1503 
1504     OhciTransfer->NextTD = TD;
1505     OhciEndpoint->HcdTailP = TD;
1506 
1507     OhciEndpoint->HcdED->HwED.TailPointer = TD->PhysicalAddress;
1508 
1509     OHCI_EnableList(OhciExtension, OhciEndpoint);
1510 
1511     return MP_STATUS_SUCCESS;
1512 }
1513 
1514 /**
1515  * @brief      Creates the transfer descriptor chain for the given transfer's buffer
1516  *             and attaches it to a given endpoint (for control, bulk or interrupt transfers)
1517  *
1518  * @param[in]  OhciExtension       The ohci extension
1519  * @param[in]  OhciEndpoint        The ohci endpoint
1520  * @param[in]  TransferParameters  The transfer parameters
1521  * @param[in]  OhciTransfer        The ohci transfer
1522  * @param[in]  SGList              The scatter/gather list
1523  *
1524  * @return     MP_STATUS_SUCCESS or MP_STATUS_FAILURE if there are not enough TDs left
1525  *             or wrong transfer type given
1526  */
1527 MPSTATUS
1528 NTAPI
1529 OHCI_SubmitTransfer(IN PVOID ohciExtension,
1530                     IN PVOID ohciEndpoint,
1531                     IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1532                     IN PVOID ohciTransfer,
1533                     IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1534 {
1535     POHCI_EXTENSION OhciExtension = ohciExtension;
1536     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1537     POHCI_TRANSFER OhciTransfer = ohciTransfer;
1538     ULONG TransferType;
1539 
1540     DPRINT_OHCI("OHCI_SubmitTransfer: ... \n");
1541 
1542     RtlZeroMemory(OhciTransfer, sizeof(OHCI_TRANSFER));
1543 
1544     OhciTransfer->TransferParameters = TransferParameters;
1545     OhciTransfer->OhciEndpoint = OhciEndpoint;
1546 
1547     TransferType = OhciEndpoint->EndpointProperties.TransferType;
1548 
1549     if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
1550     {
1551         return OHCI_ControlTransfer(OhciExtension,
1552                                     OhciEndpoint,
1553                                     TransferParameters,
1554                                     OhciTransfer,
1555                                     SGList);
1556     }
1557 
1558     if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
1559         TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1560     {
1561         return OHCI_BulkOrInterruptTransfer(OhciExtension,
1562                                             OhciEndpoint,
1563                                             TransferParameters,
1564                                             OhciTransfer,
1565                                             SGList);
1566     }
1567 
1568     return MP_STATUS_FAILURE;
1569 }
1570 
1571 MPSTATUS
1572 NTAPI
1573 OHCI_SubmitIsoTransfer(IN PVOID ohciExtension,
1574                        IN PVOID ohciEndpoint,
1575                        IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1576                        IN PVOID ohciTransfer,
1577                        IN PVOID isoParameters)
1578 {
1579     DPRINT1("OHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n");
1580     return MP_STATUS_SUCCESS;
1581 }
1582 
1583 VOID
1584 NTAPI
1585 OHCI_ProcessDoneTD(IN POHCI_EXTENSION OhciExtension,
1586                    IN POHCI_HCD_TD TD,
1587                    IN BOOLEAN IsPortComplete)
1588 {
1589     POHCI_TRANSFER OhciTransfer;
1590     POHCI_ENDPOINT OhciEndpoint;
1591     ULONG Buffer;
1592     ULONG BufferEnd;
1593     ULONG Length;
1594 
1595     DPRINT_OHCI("OHCI_ProcessDoneTD: ... \n");
1596 
1597     OhciTransfer = TD->OhciTransfer;
1598     OhciEndpoint = OhciTransfer->OhciEndpoint;
1599 
1600     OhciTransfer->PendingTDs--;
1601 
1602     Buffer = TD->HwTD.gTD.CurrentBuffer;
1603     BufferEnd = TD->HwTD.gTD.BufferEnd;
1604 
1605     if (TD->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1606     {
1607         TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
1608     }
1609     else
1610     {
1611         if (TD->HwTD.gTD.CurrentBuffer)
1612         {
1613             if (TD->TransferLen)
1614             {
1615                 Length = (BufferEnd & (PAGE_SIZE - 1)) -
1616                          (Buffer & (PAGE_SIZE - 1));
1617 
1618                 Length++;
1619 
1620                 if (Buffer >> PAGE_SHIFT != BufferEnd >> PAGE_SHIFT)
1621                     Length += PAGE_SIZE;
1622 
1623                 TD->TransferLen -= Length;
1624             }
1625         }
1626 
1627         if (TD->HwTD.gTD.Control.DirectionPID != OHCI_TD_DIRECTION_PID_SETUP)
1628             OhciTransfer->TransferLen += TD->TransferLen;
1629 
1630         if (TD->HwTD.gTD.Control.ConditionCode)
1631         {
1632             OhciTransfer->USBDStatus = USBD_STATUS_HALTED |
1633                                        TD->HwTD.gTD.Control.ConditionCode;
1634         }
1635     }
1636 
1637     TD->Flags = 0;
1638     TD->HwTD.gTD.NextTD = 0;
1639     TD->OhciTransfer = 0;
1640 
1641     TD->DoneLink.Flink = NULL;
1642     TD->DoneLink.Blink = NULL;
1643 
1644     if (IsPortComplete && (OhciTransfer->PendingTDs == 0))
1645     {
1646         RegPacket.UsbPortCompleteTransfer(OhciExtension,
1647                                           OhciEndpoint,
1648                                           OhciTransfer->TransferParameters,
1649                                           OhciTransfer->USBDStatus,
1650                                           OhciTransfer->TransferLen);
1651     }
1652 }
1653 
1654 VOID
1655 NTAPI
1656 OHCI_ProcessDoneIsoTD(IN POHCI_EXTENSION OhciExtension,
1657                       IN POHCI_HCD_TD TD,
1658                       IN BOOLEAN IsPortComplete)
1659 {
1660     DPRINT1("OHCI_ProcessDoneIsoTD: UNIMPLEMENTED. FIXME\n");
1661 }
1662 
1663 /**
1664  * @brief      Aborts the transfer descriptor chain in a given endpoint
1665  *
1666  * @param[in]  ohciExtension   The ohci extension
1667  * @param[in]  ohciEndpoint    The ohci endpoint
1668  * @param[in]  ohciTransfer    The ohci transfer
1669  * @param[out] CompletedLength
1670  */
1671 VOID
1672 NTAPI
1673 OHCI_AbortTransfer(IN PVOID ohciExtension,
1674                    IN PVOID ohciEndpoint,
1675                    IN PVOID ohciTransfer,
1676                    IN OUT PULONG CompletedLength)
1677 {
1678     POHCI_EXTENSION OhciExtension = ohciExtension;
1679     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1680     POHCI_TRANSFER OhciTransfer = ohciTransfer;
1681     POHCI_HCD_ED ED = OhciEndpoint->HcdED;
1682     POHCI_HCD_TD TD, NextTD, LastTD;
1683     ULONG ix;
1684     BOOLEAN IsIsoEndpoint;
1685     BOOLEAN IsProcessed = FALSE;
1686 
1687     DPRINT("OHCI_AbortTransfer: ohciEndpoint - %p, ohciTransfer - %p\n",
1688            OhciEndpoint,
1689            OhciTransfer);
1690 
1691     IsIsoEndpoint = (OhciEndpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS);
1692     NextTD = RegPacket.UsbPortGetMappedVirtualAddress(ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK,
1693                                                       OhciExtension,
1694                                                       OhciEndpoint);
1695 
1696     if (NextTD->OhciTransfer == OhciTransfer)
1697     {
1698         LastTD = OhciTransfer->NextTD;
1699 
1700         /* Keeping the carry bit from previous pointer value */
1701         ED->HwED.HeadPointer = LastTD->PhysicalAddress |
1702                                (ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_CARRY);
1703 
1704         OhciEndpoint->HcdHeadP = LastTD;
1705 
1706         for (ix = 0; ix < OhciEndpoint->MaxTransferDescriptors; ix++)
1707         {
1708             TD = &OhciEndpoint->FirstTD[ix];
1709 
1710             if (TD->OhciTransfer != OhciTransfer)
1711                 continue;
1712 
1713             if (IsIsoEndpoint)
1714                 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1715             else
1716                 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1717         }
1718 
1719         *CompletedLength = OhciTransfer->TransferLen;
1720         return;
1721     }
1722 
1723     if (NextTD == OhciEndpoint->HcdHeadP)
1724         IsProcessed = TRUE;
1725 
1726     for (TD = OhciEndpoint->HcdHeadP; TD != NextTD; TD = TD->NextTDVa)
1727     {
1728         if (TD->OhciTransfer != OhciTransfer)
1729             continue;
1730 
1731         if (OhciEndpoint->HcdHeadP == TD)
1732             OhciEndpoint->HcdHeadP = TD->NextTDVa;
1733 
1734         if (IsIsoEndpoint)
1735             OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1736         else
1737             OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1738 
1739         IsProcessed = TRUE;
1740     }
1741 
1742     if (!IsProcessed)
1743     {
1744         for (TD = OhciEndpoint->HcdHeadP; TD->OhciTransfer != OhciTransfer; TD = TD->NextTDVa)
1745         {
1746             if (TD == OhciEndpoint->HcdTailP)
1747             {
1748                 TD = NULL;
1749                 break;
1750             }
1751             LastTD = TD;
1752         }
1753 
1754         for (; TD->OhciTransfer == OhciTransfer; TD = TD->NextTDVa)
1755         {
1756             if (TD == OhciEndpoint->HcdTailP)
1757                 break;
1758 
1759             if (IsIsoEndpoint)
1760                 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1761             else
1762                 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1763         }
1764 
1765         LastTD->OhciTransfer->NextTD = TD;
1766 
1767         LastTD->NextTDVa = TD;
1768         LastTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1769     }
1770 
1771     *CompletedLength = OhciTransfer->TransferLen;
1772 
1773     if (OhciTransfer->TransferLen)
1774     {
1775         DPRINT("OHCI_AbortTransfer: *CompletedLength - %x\n", *CompletedLength);
1776     }
1777 }
1778 
1779 ULONG
1780 NTAPI
1781 OHCI_GetEndpointState(IN PVOID ohciExtension,
1782                       IN PVOID ohciEndpoint)
1783 {
1784     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1785     POHCI_HCD_ED ED;
1786 
1787     DPRINT_OHCI("OHCI_GetEndpointState: ... \n");
1788 
1789     ED = OhciEndpoint->HcdED;
1790 
1791     if (ED->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1792         return USBPORT_ENDPOINT_REMOVE;
1793 
1794     if (ED->HwED.EndpointControl.sKip)
1795         return USBPORT_ENDPOINT_PAUSED;
1796 
1797     return USBPORT_ENDPOINT_ACTIVE;
1798 }
1799 
1800 VOID
1801 NTAPI
1802 OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint)
1803 {
1804     POHCI_HCD_ED ED;
1805     POHCI_HCD_ED PreviousED;
1806     POHCI_STATIC_ED HeadED;
1807 
1808     DPRINT_OHCI("OHCI_RemoveEndpointFromSchedule \n");
1809 
1810     ED = OhciEndpoint->HcdED;
1811     HeadED = OhciEndpoint->HeadED;
1812 
1813     if (&HeadED->Link == ED->HcdEDLink.Blink)
1814     {
1815         if (HeadED->Type == OHCI_STATIC_ED_TYPE_CONTROL ||
1816             HeadED->Type == OHCI_STATIC_ED_TYPE_BULK)
1817         {
1818             WRITE_REGISTER_ULONG(HeadED->pNextED, ED->HwED.NextED);
1819         }
1820         else if (HeadED->Type == OHCI_STATIC_ED_TYPE_INTERRUPT)
1821         {
1822             *HeadED->pNextED = ED->HwED.NextED;
1823         }
1824         else
1825         {
1826             DPRINT1("OHCI_RemoveEndpointFromSchedule: Unknown HeadED->Type - %x\n",
1827                     HeadED->Type);
1828             DbgBreakPoint();
1829         }
1830     }
1831     else
1832     {
1833         PreviousED = CONTAINING_RECORD(ED->HcdEDLink.Blink,
1834                                        OHCI_HCD_ED,
1835                                        HcdEDLink);
1836 
1837         PreviousED->HwED.NextED = ED->HwED.NextED;
1838     }
1839 
1840     RemoveEntryList(&ED->HcdEDLink);
1841 
1842     OhciEndpoint->HeadED = NULL;
1843 }
1844 
1845 VOID
1846 NTAPI
1847 OHCI_SetEndpointState(IN PVOID ohciExtension,
1848                       IN PVOID ohciEndpoint,
1849                       IN ULONG EndpointState)
1850 {
1851     POHCI_EXTENSION OhciExtension = ohciExtension;
1852     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1853     POHCI_HCD_ED ED;
1854 
1855     DPRINT_OHCI("OHCI_SetEndpointState: EndpointState - %x\n",
1856                 EndpointState);
1857 
1858     ED = OhciEndpoint->HcdED;
1859 
1860     switch (EndpointState)
1861     {
1862         case USBPORT_ENDPOINT_PAUSED:
1863             ED->HwED.EndpointControl.sKip = 1;
1864             break;
1865 
1866         case USBPORT_ENDPOINT_ACTIVE:
1867             ED->HwED.EndpointControl.sKip = 0;
1868             OHCI_EnableList(OhciExtension, OhciEndpoint);
1869             break;
1870 
1871         case USBPORT_ENDPOINT_REMOVE:
1872             ED->HwED.EndpointControl.sKip = 1;
1873             ED->Flags |= OHCI_HCD_ED_FLAG_NOT_ACCESSED;
1874             OHCI_RemoveEndpointFromSchedule(OhciEndpoint);
1875             break;
1876 
1877         default:
1878             ASSERT(FALSE);
1879             break;
1880     }
1881 }
1882 
1883 VOID
1884 NTAPI
1885 OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension,
1886                        IN POHCI_ENDPOINT OhciEndpoint)
1887 {
1888     PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1889     POHCI_HCD_ED ED;
1890     ULONG_PTR NextTdPA;
1891     POHCI_HCD_TD NextTD;
1892     POHCI_HCD_TD TD;
1893     PLIST_ENTRY DoneList;
1894     POHCI_TRANSFER OhciTransfer;
1895     POHCI_HCD_TD ControlStatusTD;
1896     ULONG_PTR PhysicalAddress;
1897     ULONG TransferNumber;
1898     POHCI_TRANSFER transfer;
1899     UCHAR ConditionCode;
1900     BOOLEAN IsResetOnHalt = FALSE;
1901 
1902     //DPRINT_OHCI("OHCI_PollAsyncEndpoint: Endpoint - %p\n", OhciEndpoint);
1903 
1904     ED = OhciEndpoint->HcdED;
1905     NextTdPA = ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK;
1906 
1907     if (!NextTdPA)
1908     {
1909         OHCI_DumpHcdED(ED);
1910         DbgBreakPoint();
1911     }
1912 
1913     NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA,
1914                                                       OhciExtension,
1915                                                       OhciEndpoint);
1916     DPRINT_OHCI("NextTD - %p\n", NextTD);
1917 
1918     if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) == 0)
1919         goto ProcessListTDs;
1920 
1921     OHCI_DumpHcdED(ED);
1922 
1923     IsResetOnHalt = (ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT) != 0;
1924     DPRINT1("PollAsyncEndpoint: IsResetOnHalt %x\n", IsResetOnHalt);
1925 
1926     for (TD = OhciEndpoint->HcdHeadP; ; TD = TD->NextTDVa)
1927     {
1928         if (!TD)
1929         {
1930             OHCI_DumpHcdED(ED);
1931             DbgBreakPoint();
1932         }
1933 
1934         if (TD == NextTD)
1935         {
1936             DPRINT("TD == NextTD - %p\n", TD);
1937             goto HandleDoneList;
1938         }
1939 
1940         OhciTransfer = TD->OhciTransfer;
1941         ConditionCode = TD->HwTD.gTD.Control.ConditionCode;
1942 
1943         DPRINT("TD - %p, ConditionCode - %X\n", TD, ConditionCode);
1944         OHCI_DumpHcdTD(TD);
1945 
1946         switch (ConditionCode)
1947         {
1948             case OHCI_TD_CONDITION_NO_ERROR:
1949                 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
1950                 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1951                 continue;
1952 
1953             case OHCI_TD_CONDITION_NOT_ACCESSED:
1954                 TD->Flags |= (OHCI_HCD_TD_FLAG_DONE | OHCI_HCD_TD_FLAG_NOT_ACCESSED);
1955                 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1956                 continue;
1957 
1958             case OHCI_TD_CONDITION_DATA_UNDERRUN:
1959                 DPRINT1("DATA_UNDERRUN. Transfer->Flags - %X\n", OhciTransfer->Flags);
1960 
1961                 if (OhciTransfer->Flags & OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK)
1962                 {
1963                     IsResetOnHalt = TRUE;
1964                     TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
1965 
1966                     ControlStatusTD = OhciTransfer->ControlStatusTD;
1967 
1968                     if ((TD->Flags & OHCI_HCD_TD_FLAG_CONTROL_STATUS) == 0 &&
1969                         ControlStatusTD)
1970                     {
1971                         PhysicalAddress = ControlStatusTD->PhysicalAddress;
1972                         PhysicalAddress |= (ED->HwED.HeadPointer &
1973                                             OHCI_ED_HEAD_POINTER_FLAGS_MASK);
1974 
1975                         ED->HwED.HeadPointer = PhysicalAddress;
1976 
1977                         NextTD = OhciTransfer->ControlStatusTD;
1978                         DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
1979                     }
1980                     else
1981                     {
1982                         TransferParameters = OhciTransfer->TransferParameters;
1983 
1984                         if (TransferParameters->IsTransferSplited)
1985                         {
1986                             TransferNumber = TransferParameters->TransferCounter;
1987                             transfer = OhciTransfer;
1988 
1989                             do
1990                             {
1991                                 transfer = transfer->NextTD->OhciTransfer;
1992                                 NextTD = transfer->NextTD;
1993                             }
1994                             while (transfer && TransferNumber ==
1995                                    transfer->TransferParameters->TransferCounter);
1996 
1997                             PhysicalAddress = NextTD->PhysicalAddress;
1998                             PhysicalAddress |= (ED->HwED.HeadPointer &
1999                                                 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2000 
2001                             ED->HwED.HeadPointer = PhysicalAddress;
2002                             DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2003                         }
2004                         else
2005                         {
2006                             PhysicalAddress = OhciTransfer->NextTD->PhysicalAddress;
2007                             PhysicalAddress |= (ED->HwED.HeadPointer &
2008                                                 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2009 
2010                             ED->HwED.HeadPointer = PhysicalAddress;
2011 
2012                             NextTD = OhciTransfer->NextTD;
2013                             DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2014                         }
2015                     }
2016 
2017                     TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2018                     InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2019                     continue;
2020                 }
2021 
2022                 /* fall through */
2023 
2024             default:
2025                 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2026                 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2027 
2028                 ED->HwED.HeadPointer = OhciTransfer->NextTD->PhysicalAddress |
2029                                        (ED->HwED.HeadPointer &
2030                                         OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2031 
2032                 NextTD = OhciTransfer->NextTD;
2033                 break;
2034         }
2035     }
2036 
2037 ProcessListTDs:
2038 
2039     TD = OhciEndpoint->HcdHeadP;
2040 
2041     while (TD != NextTD)
2042     {
2043         OHCI_DumpHcdTD(TD);
2044         TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2045         InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2046         TD = TD->NextTDVa;
2047     }
2048 
2049 HandleDoneList:
2050 
2051     TD = NextTD;
2052     OhciEndpoint->HcdHeadP = NextTD;
2053 
2054     DoneList = &OhciEndpoint->TDList;
2055 
2056     while (!IsListEmpty(DoneList))
2057     {
2058         TD = CONTAINING_RECORD(DoneList->Flink,
2059                                OHCI_HCD_TD,
2060                                DoneLink);
2061 
2062         RemoveHeadList(DoneList);
2063 
2064         if (TD->Flags & OHCI_HCD_TD_FLAG_DONE &&
2065             TD->Flags & OHCI_HCD_TD_FLAG_PROCESSED)
2066         {
2067             OHCI_ProcessDoneTD(OhciExtension, TD, TRUE);
2068         }
2069     }
2070 
2071     if (IsResetOnHalt)
2072     {
2073         ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2074         DPRINT("ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer);
2075     }
2076 }
2077 
2078 VOID
2079 NTAPI
2080 OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension,
2081                      IN POHCI_ENDPOINT OhciEndpoint)
2082 {
2083     DPRINT1("OHCI_PollAsyncEndpoint: UNIMPLEMENTED. FIXME \n");
2084     ASSERT(FALSE);
2085 }
2086 
2087 VOID
2088 NTAPI
2089 OHCI_PollEndpoint(IN PVOID ohciExtension,
2090                   IN PVOID ohciEndpoint)
2091 {
2092     POHCI_EXTENSION OhciExtension = ohciExtension;
2093     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2094     ULONG TransferType;
2095 
2096     DPRINT_OHCI("OHCI_PollEndpoint: OhciExtension - %p, Endpoint - %p\n",
2097                 OhciExtension,
2098                 OhciEndpoint);
2099 
2100     TransferType = OhciEndpoint->EndpointProperties.TransferType;
2101 
2102     if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2103     {
2104         OHCI_PollIsoEndpoint(OhciExtension, OhciEndpoint);
2105         return;
2106     }
2107 
2108     if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2109         TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2110         TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2111     {
2112         OHCI_PollAsyncEndpoint(OhciExtension, OhciEndpoint);
2113     }
2114 }
2115 
2116 VOID
2117 NTAPI
2118 OHCI_CheckController(IN PVOID ohciExtension)
2119 {
2120     POHCI_EXTENSION OhciExtension = ohciExtension;
2121     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2122     PULONG HcControlReg;
2123     OHCI_REG_CONTROL HcControl;
2124     ULONG FmNumber;
2125     USHORT FmDiff;
2126     POHCI_HCCA HcHCCA;
2127 
2128     //DPRINT_OHCI("OHCI_CheckController: ...\n");
2129 
2130     OperationalRegs = OhciExtension->OperationalRegs;
2131 
2132     if (!OHCI_HardwarePresent(OhciExtension, TRUE))
2133         return;
2134 
2135     HcControlReg = (PULONG)&OperationalRegs->HcControl;
2136     HcControl.AsULONG = READ_REGISTER_ULONG(HcControlReg);
2137 
2138     if (HcControl.HostControllerFunctionalState != OHCI_HC_STATE_OPERATIONAL)
2139         return;
2140 
2141     FmNumber = READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber);
2142     FmDiff = (USHORT)(FmNumber - OhciExtension->HcdFmNumber);
2143 
2144     if (FmNumber == 0 || FmDiff < 5)
2145         return;
2146 
2147     HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2148     OhciExtension->HcdFmNumber = FmNumber;
2149 
2150     if (HcHCCA->Pad1 == 0)
2151     {
2152         HcHCCA->Pad1 = 0xBAD1;
2153         return;
2154     }
2155 
2156     DPRINT1("OHCI_CheckController: HcHCCA->Pad1 - %x\n", HcHCCA->Pad1);
2157 
2158     if (HcHCCA->Pad1 == 0xBAD1)
2159     {
2160         HcHCCA->Pad1 = 0xBAD2;
2161     }
2162     else if (HcHCCA->Pad1 == 0xBAD2)
2163     {
2164         HcHCCA->Pad1 = 0xBAD3;
2165 
2166         RegPacket.UsbPortInvalidateController(OhciExtension,
2167                                               USBPORT_INVALIDATE_CONTROLLER_RESET);
2168     }
2169 }
2170 
2171 ULONG
2172 NTAPI
2173 OHCI_Get32BitFrameNumber(IN PVOID ohciExtension)
2174 {
2175     POHCI_EXTENSION OhciExtension = ohciExtension;
2176     POHCI_HCCA HcHCCA;
2177     ULONG fm;
2178     ULONG hp;
2179 
2180     HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2181 
2182     /* 5.4 FrameInterval Counter: Get32BitFrameNumber() */
2183 
2184     hp = OhciExtension->FrameHighPart;
2185     fm = HcHCCA->FrameNumber;
2186 
2187     DPRINT_OHCI("OHCI_Get32BitFrameNumber: hp - %lX, fm - %lX\n", hp, fm);
2188 
2189     return ((fm & 0x7FFF) | hp) + ((fm ^ hp) & 0x8000);
2190 }
2191 
2192 VOID
2193 NTAPI
2194 OHCI_InterruptNextSOF(IN PVOID ohciExtension)
2195 {
2196     POHCI_EXTENSION OhciExtension = ohciExtension;
2197     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2198     PULONG InterruptEnableReg;
2199     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2200 
2201     DPRINT_OHCI("OHCI_InterruptNextSOF: OhciExtension - %p\n",
2202                 OhciExtension);
2203 
2204     OperationalRegs = OhciExtension->OperationalRegs;
2205     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2206 
2207     /* Enable interrupt generation due to Start of Frame */
2208     IntEnable.AsULONG = 0;
2209     IntEnable.StartofFrame = 1;
2210 
2211     WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2212 }
2213 
2214 VOID
2215 NTAPI
2216 OHCI_EnableInterrupts(IN PVOID ohciExtension)
2217 {
2218     POHCI_EXTENSION OhciExtension = ohciExtension;
2219     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2220     PULONG InterruptEnableReg;
2221     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2222 
2223     DPRINT_OHCI("OHCI_EnableInterrupts: OhciExtension - %p\n",
2224                 OhciExtension);
2225 
2226     OperationalRegs = OhciExtension->OperationalRegs;
2227     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2228 
2229     /*  Enable interrupt generation */
2230     IntEnable.AsULONG = 0;
2231     IntEnable.MasterInterruptEnable = 1;
2232 
2233     WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2234 }
2235 
2236 VOID
2237 NTAPI
2238 OHCI_DisableInterrupts(IN PVOID ohciExtension)
2239 {
2240     POHCI_EXTENSION  OhciExtension = ohciExtension;
2241     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2242     PULONG InterruptDisableReg;
2243     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
2244 
2245     DPRINT_OHCI("OHCI_DisableInterrupts\n");
2246 
2247     OperationalRegs = OhciExtension->OperationalRegs;
2248     InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
2249 
2250     /*  Disable interrupt generation */
2251     IntDisable.AsULONG = 0;
2252     IntDisable.MasterInterruptEnable = 1;
2253 
2254     WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
2255 }
2256 
2257 VOID
2258 NTAPI
2259 OHCI_PollController(IN PVOID ohciExtension)
2260 {
2261     DPRINT1("OHCI_PollController: UNIMPLEMENTED. FIXME\n");
2262 }
2263 
2264 VOID
2265 NTAPI
2266 OHCI_SetEndpointDataToggle(IN PVOID ohciExtension,
2267                            IN PVOID ohciEndpoint,
2268                            IN ULONG DataToggle)
2269 {
2270     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2271     POHCI_HCD_ED ED;
2272 
2273     DPRINT_OHCI("OHCI_SetEndpointDataToggle: Endpoint - %p, DataToggle - %x\n",
2274                 OhciEndpoint,
2275                 DataToggle);
2276 
2277     ED = OhciEndpoint->HcdED;
2278 
2279     if (DataToggle)
2280         ED->HwED.HeadPointer |= OHCI_ED_HEAD_POINTER_CARRY;
2281     else
2282         ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_CARRY;
2283 }
2284 
2285 ULONG
2286 NTAPI
2287 OHCI_GetEndpointStatus(IN PVOID ohciExtension,
2288                        IN PVOID ohciEndpoint)
2289 {
2290     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2291     POHCI_HCD_ED ED;
2292     ULONG EndpointStatus = USBPORT_ENDPOINT_RUN;
2293 
2294     DPRINT_OHCI("OHCI_GetEndpointStatus: ... \n");
2295 
2296     ED = OhciEndpoint->HcdED;
2297 
2298     if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) &&
2299         !(ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT))
2300     {
2301         EndpointStatus = USBPORT_ENDPOINT_HALT;
2302     }
2303 
2304     return EndpointStatus;
2305 }
2306 
2307 VOID
2308 NTAPI
2309 OHCI_SetEndpointStatus(IN PVOID ohciExtension,
2310                        IN PVOID ohciEndpoint,
2311                        IN ULONG EndpointStatus)
2312 {
2313     POHCI_EXTENSION OhciExtension = ohciExtension;
2314     POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2315     POHCI_HCD_ED ED;
2316 
2317     DPRINT_OHCI("OHCI_SetEndpointStatus: Endpoint - %p, EndpointStatus - %lX\n",
2318                 OhciEndpoint,
2319                 EndpointStatus);
2320 
2321     if (EndpointStatus == USBPORT_ENDPOINT_RUN)
2322     {
2323         ED = OhciEndpoint->HcdED;
2324         ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2325 
2326         OHCI_EnableList(OhciExtension, OhciEndpoint);
2327     }
2328     else if (EndpointStatus == USBPORT_ENDPOINT_HALT)
2329     {
2330         ASSERT(FALSE);
2331     }
2332 }
2333 
2334 VOID
2335 NTAPI
2336 OHCI_ResetController(IN PVOID ohciExtension)
2337 {
2338     POHCI_EXTENSION OhciExtension = ohciExtension;
2339     POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2340     ULONG FrameNumber;
2341     PULONG ControlReg;
2342     PULONG CommandStatusReg;
2343     PULONG InterruptEnableReg;
2344     PULONG FmIntervalReg;
2345     PULONG RhStatusReg;
2346     PULONG PortStatusReg;
2347     OHCI_REG_CONTROL ControlBak;
2348     OHCI_REG_CONTROL Control;
2349     OHCI_REG_COMMAND_STATUS CommandStatus;
2350     OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2351     ULONG_PTR HCCA;
2352     ULONG_PTR ControlHeadED;
2353     ULONG_PTR BulkHeadED;
2354     OHCI_REG_FRAME_INTERVAL FrameInterval;
2355     ULONG_PTR PeriodicStart;
2356     ULONG_PTR LSThreshold;
2357     OHCI_REG_RH_STATUS RhStatus;
2358     OHCI_REG_RH_DESCRIPTORA RhDescriptorA;
2359     OHCI_REG_RH_PORT_STATUS PortStatus;
2360     ULONG NumPorts;
2361     ULONG ix;
2362 
2363     DPRINT("OHCI_ResetController: ... \n");
2364 
2365     OperationalRegs = OhciExtension->OperationalRegs;
2366 
2367     ControlReg = (PULONG)&OperationalRegs->HcControl;
2368     CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
2369     InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2370     FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
2371     RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
2372 
2373     /* Backup FrameNumber from HcHCCA */
2374     FrameNumber = OhciExtension->HcResourcesVA->HcHCCA.FrameNumber;
2375 
2376     /* Backup registers */
2377     ControlBak.AsULONG = READ_REGISTER_ULONG(ControlReg);
2378     HCCA = READ_REGISTER_ULONG(&OperationalRegs->HcHCCA);
2379     ControlHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcControlHeadED);
2380     BulkHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED);
2381     FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
2382     PeriodicStart = READ_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart);
2383     LSThreshold = READ_REGISTER_ULONG(&OperationalRegs->HcLSThreshold);
2384 
2385     /* Reset HostController */
2386     CommandStatus.AsULONG = 0;
2387     CommandStatus.HostControllerReset = 1;
2388     WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
2389 
2390     KeStallExecutionProcessor(10);
2391 
2392     /* Restore registers */
2393     WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA, HCCA);
2394     WRITE_REGISTER_ULONG(&OperationalRegs->HcControlHeadED, ControlHeadED);
2395     WRITE_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED, BulkHeadED);
2396 
2397     /* Set OPERATIONAL state for HC */
2398     Control.AsULONG = 0;
2399     Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2400     WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
2401 
2402     /* Set Toggle bit for FmInterval register */
2403     FrameInterval.FrameIntervalToggle = 1;
2404     WRITE_REGISTER_ULONG(FmIntervalReg, FrameInterval.AsULONG);
2405 
2406     /* Restore registers */
2407     WRITE_REGISTER_ULONG(&OperationalRegs->HcFmNumber, FrameNumber);
2408     WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart, PeriodicStart);
2409     WRITE_REGISTER_ULONG(&OperationalRegs->HcLSThreshold, LSThreshold);
2410 
2411     /* Setup RhStatus register */
2412     RhStatus.AsULONG = 0;
2413     RhStatus.SetRemoteWakeupEnable = 1;
2414     RhStatus.SetGlobalPower = 1;
2415     WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
2416 
2417     /* Setup RH PortStatus registers */
2418     RhDescriptorA = OHCI_ReadRhDescriptorA(OhciExtension);
2419     NumPorts = RhDescriptorA.NumberDownstreamPorts;
2420 
2421     PortStatus.AsULONG = 0;
2422     PortStatus.SetPortPower = 1;
2423 
2424     for (ix = 0; ix < NumPorts; ix++)
2425     {
2426         PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[ix];
2427         WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG);
2428     }
2429 
2430     /* Restore HcControl register */
2431     ControlBak.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2432     WRITE_REGISTER_ULONG(ControlReg, ControlBak.AsULONG);
2433 
2434     /* Setup HcInterruptEnable register */
2435     IntEnable.AsULONG = 0xFFFFFFFF;
2436     IntEnable.Reserved1 = 0;
2437     WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2438 }
2439 
2440 MPSTATUS
2441 NTAPI
2442 OHCI_StartSendOnePacket(IN PVOID ohciExtension,
2443                         IN PVOID PacketParameters,
2444                         IN PVOID Data,
2445                         IN PULONG pDataLength,
2446                         IN PVOID BufferVA,
2447                         IN PVOID BufferPA,
2448                         IN ULONG BufferLength,
2449                         IN USBD_STATUS * pUSBDStatus)
2450 {
2451     DPRINT1("OHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n");
2452     return MP_STATUS_SUCCESS;
2453 }
2454 
2455 MPSTATUS
2456 NTAPI
2457 OHCI_EndSendOnePacket(IN PVOID ohciExtension,
2458                       IN PVOID PacketParameters,
2459                       IN PVOID Data,
2460                       IN PULONG pDataLength,
2461                       IN PVOID BufferVA,
2462                       IN PVOID BufferPA,
2463                       IN ULONG BufferLength,
2464                       IN USBD_STATUS * pUSBDStatus)
2465 {
2466     DPRINT1("OHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n");
2467     return MP_STATUS_SUCCESS;
2468 }
2469 
2470 MPSTATUS
2471 NTAPI
2472 OHCI_PassThru(IN PVOID ohciExtension,
2473               IN PVOID passThruParameters,
2474               IN ULONG ParameterLength,
2475               IN PVOID pParameters)
2476 {
2477     DPRINT1("OHCI_PassThru: UNIMPLEMENTED. FIXME\n");
2478     return MP_STATUS_SUCCESS;
2479 }
2480 
2481 VOID
2482 NTAPI
2483 OHCI_Unload(IN PDRIVER_OBJECT DriverObject)
2484 {
2485 #if DBG
2486     DPRINT1("OHCI_Unload: Not supported\n");
2487 #endif
2488     return;
2489 }
2490 
2491 VOID
2492 NTAPI
2493 OHCI_FlushInterrupts(IN PVOID uhciExtension)
2494 {
2495 #if DBG
2496     DPRINT1("OHCI_FlushInterrupts: Not supported\n");
2497 #endif
2498     return;
2499 }
2500 
2501 NTSTATUS
2502 NTAPI
2503 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2504             IN PUNICODE_STRING RegistryPath)
2505 {
2506     NTSTATUS Status;
2507 
2508     DPRINT_OHCI("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n",
2509                 DriverObject,
2510                 RegistryPath);
2511 
2512     RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET));
2513 
2514     RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_OHCI;
2515 
2516     RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT |
2517                               USB_MINIPORT_FLAGS_MEMORY_IO;
2518 
2519     RegPacket.MiniPortBusBandwidth = TOTAL_USB11_BUS_BANDWIDTH;
2520 
2521     RegPacket.MiniPortExtensionSize = sizeof(OHCI_EXTENSION);
2522     RegPacket.MiniPortEndpointSize = sizeof(OHCI_ENDPOINT);
2523     RegPacket.MiniPortTransferSize = sizeof(OHCI_TRANSFER);
2524     RegPacket.MiniPortResourcesSize = sizeof(OHCI_HC_RESOURCES);
2525 
2526     RegPacket.OpenEndpoint = OHCI_OpenEndpoint;
2527     RegPacket.ReopenEndpoint = OHCI_ReopenEndpoint;
2528     RegPacket.QueryEndpointRequirements = OHCI_QueryEndpointRequirements;
2529     RegPacket.CloseEndpoint = OHCI_CloseEndpoint;
2530     RegPacket.StartController = OHCI_StartController;
2531     RegPacket.StopController = OHCI_StopController;
2532     RegPacket.SuspendController = OHCI_SuspendController;
2533     RegPacket.ResumeController = OHCI_ResumeController;
2534     RegPacket.InterruptService = OHCI_InterruptService;
2535     RegPacket.InterruptDpc = OHCI_InterruptDpc;
2536     RegPacket.SubmitTransfer = OHCI_SubmitTransfer;
2537     RegPacket.SubmitIsoTransfer = OHCI_SubmitIsoTransfer;
2538     RegPacket.AbortTransfer = OHCI_AbortTransfer;
2539     RegPacket.GetEndpointState = OHCI_GetEndpointState;
2540     RegPacket.SetEndpointState = OHCI_SetEndpointState;
2541     RegPacket.PollEndpoint = OHCI_PollEndpoint;
2542     RegPacket.CheckController = OHCI_CheckController;
2543     RegPacket.Get32BitFrameNumber = OHCI_Get32BitFrameNumber;
2544     RegPacket.InterruptNextSOF = OHCI_InterruptNextSOF;
2545     RegPacket.EnableInterrupts = OHCI_EnableInterrupts;
2546     RegPacket.DisableInterrupts = OHCI_DisableInterrupts;
2547     RegPacket.PollController = OHCI_PollController;
2548     RegPacket.SetEndpointDataToggle = OHCI_SetEndpointDataToggle;
2549     RegPacket.GetEndpointStatus = OHCI_GetEndpointStatus;
2550     RegPacket.SetEndpointStatus = OHCI_SetEndpointStatus;
2551     RegPacket.ResetController = OHCI_ResetController;
2552     RegPacket.RH_GetRootHubData = OHCI_RH_GetRootHubData;
2553     RegPacket.RH_GetStatus = OHCI_RH_GetStatus;
2554     RegPacket.RH_GetPortStatus = OHCI_RH_GetPortStatus;
2555     RegPacket.RH_GetHubStatus = OHCI_RH_GetHubStatus;
2556     RegPacket.RH_SetFeaturePortReset = OHCI_RH_SetFeaturePortReset;
2557     RegPacket.RH_SetFeaturePortPower = OHCI_RH_SetFeaturePortPower;
2558     RegPacket.RH_SetFeaturePortEnable = OHCI_RH_SetFeaturePortEnable;
2559     RegPacket.RH_SetFeaturePortSuspend = OHCI_RH_SetFeaturePortSuspend;
2560     RegPacket.RH_ClearFeaturePortEnable = OHCI_RH_ClearFeaturePortEnable;
2561     RegPacket.RH_ClearFeaturePortPower = OHCI_RH_ClearFeaturePortPower;
2562     RegPacket.RH_ClearFeaturePortSuspend = OHCI_RH_ClearFeaturePortSuspend;
2563     RegPacket.RH_ClearFeaturePortEnableChange = OHCI_RH_ClearFeaturePortEnableChange;
2564     RegPacket.RH_ClearFeaturePortConnectChange = OHCI_RH_ClearFeaturePortConnectChange;
2565     RegPacket.RH_ClearFeaturePortResetChange = OHCI_RH_ClearFeaturePortResetChange;
2566     RegPacket.RH_ClearFeaturePortSuspendChange = OHCI_RH_ClearFeaturePortSuspendChange;
2567     RegPacket.RH_ClearFeaturePortOvercurrentChange = OHCI_RH_ClearFeaturePortOvercurrentChange;
2568     RegPacket.RH_DisableIrq = OHCI_RH_DisableIrq;
2569     RegPacket.RH_EnableIrq = OHCI_RH_EnableIrq;
2570     RegPacket.StartSendOnePacket = OHCI_StartSendOnePacket;
2571     RegPacket.EndSendOnePacket = OHCI_EndSendOnePacket;
2572     RegPacket.PassThru = OHCI_PassThru;
2573     RegPacket.FlushInterrupts = OHCI_FlushInterrupts;
2574 
2575     DriverObject->DriverUnload = OHCI_Unload;
2576 
2577     Status = USBPORT_RegisterUSBPortDriver(DriverObject,
2578                                            USB10_MINIPORT_INTERFACE_VERSION,
2579                                            &RegPacket);
2580 
2581     DPRINT_OHCI("DriverEntry: USBPORT_RegisterUSBPortDriver return Status - %x\n",
2582                 Status);
2583 
2584     return Status;
2585 }
2586