39986e4707084b162d1f40e33f949ca2c33d534d
[reactos.git] / drivers / usb / usbohci_new / usbohci.c
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 EndTime;
544 LARGE_INTEGER SystemTime;
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 KeQuerySystemTime(&EndTime);
600 EndTime.QuadPart += 500 * 10000; // 0.5 sec;
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 KeQuerySystemTime(&SystemTime);
622 }
623 while (SystemTime.QuadPart < EndTime.QuadPart);
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 SystemTime;
651 LARGE_INTEGER EndTime;
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 KeQuerySystemTime(&EndTime);
795 EndTime.QuadPart += 500 * 10000; // 0.5 sec
796
797 while (TRUE)
798 {
799 WRITE_REGISTER_ULONG(FmIntervalReg, OhciExtension->FrameInterval.AsULONG);
800 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
801
802 KeQuerySystemTime(&SystemTime);
803
804 if (SystemTime.QuadPart >= EndTime.QuadPart)
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 ULONG_PTR NextTdPA;
1683 POHCI_HCD_TD TD, NextTD, LastTD;
1684 ULONG ix;
1685 BOOLEAN IsIsoEndpoint;
1686 BOOLEAN IsProcessed = FALSE;
1687
1688 DPRINT("OHCI_AbortTransfer: ohciEndpoint - %p, ohciTransfer - %p\n",
1689 OhciEndpoint,
1690 OhciTransfer);
1691
1692 IsIsoEndpoint = (OhciEndpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS);
1693 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK,
1694 OhciExtension,
1695 OhciEndpoint);
1696
1697 if (NextTD->OhciTransfer == OhciTransfer)
1698 {
1699 LastTD = OhciTransfer->NextTD;
1700
1701 /* Keeping the carry bit from previous pointer value */
1702 ED->HwED.HeadPointer = LastTD->PhysicalAddress |
1703 (ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_CARRY);
1704
1705 OhciEndpoint->HcdHeadP = LastTD;
1706
1707 for (ix = 0; ix < OhciEndpoint->MaxTransferDescriptors; ix++)
1708 {
1709 TD = &OhciEndpoint->FirstTD[ix];
1710
1711 if (TD->OhciTransfer != OhciTransfer)
1712 continue;
1713
1714 if (IsIsoEndpoint)
1715 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1716 else
1717 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1718 }
1719
1720 *CompletedLength = OhciTransfer->TransferLen;
1721 return;
1722 }
1723
1724 if (NextTD == OhciEndpoint->HcdHeadP)
1725 IsProcessed = TRUE;
1726
1727 for (TD = OhciEndpoint->HcdHeadP; TD != NextTD; TD = TD->NextTDVa)
1728 {
1729 if (TD->OhciTransfer != OhciTransfer)
1730 continue;
1731
1732 if (OhciEndpoint->HcdHeadP == TD)
1733 OhciEndpoint->HcdHeadP = TD->NextTDVa;
1734
1735 if (IsIsoEndpoint)
1736 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1737 else
1738 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1739
1740 IsProcessed = TRUE;
1741 }
1742
1743 if (!IsProcessed)
1744 {
1745 for (TD = OhciEndpoint->HcdHeadP; TD->OhciTransfer != OhciTransfer; TD = TD->NextTDVa)
1746 {
1747 if (TD == OhciEndpoint->HcdTailP)
1748 {
1749 TD = NULL;
1750 break;
1751 }
1752 LastTD = TD;
1753 }
1754
1755 for (; TD->OhciTransfer == OhciTransfer; TD = TD->NextTDVa)
1756 {
1757 if (TD == OhciEndpoint->HcdTailP)
1758 break;
1759
1760 if (IsIsoEndpoint)
1761 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1762 else
1763 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1764 }
1765
1766 LastTD->OhciTransfer->NextTD = TD;
1767
1768 LastTD->NextTDVa = TD;
1769 LastTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1770 }
1771
1772 *CompletedLength = OhciTransfer->TransferLen;
1773
1774 if (OhciTransfer->TransferLen)
1775 {
1776 DPRINT("OHCI_AbortTransfer: *CompletedLength - %x\n", *CompletedLength);
1777 }
1778 }
1779
1780 ULONG
1781 NTAPI
1782 OHCI_GetEndpointState(IN PVOID ohciExtension,
1783 IN PVOID ohciEndpoint)
1784 {
1785 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1786 POHCI_HCD_ED ED;
1787
1788 DPRINT_OHCI("OHCI_GetEndpointState: ... \n");
1789
1790 ED = OhciEndpoint->HcdED;
1791
1792 if (ED->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1793 return USBPORT_ENDPOINT_REMOVE;
1794
1795 if (ED->HwED.EndpointControl.sKip)
1796 return USBPORT_ENDPOINT_PAUSED;
1797
1798 return USBPORT_ENDPOINT_ACTIVE;
1799 }
1800
1801 VOID
1802 NTAPI
1803 OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint)
1804 {
1805 POHCI_HCD_ED ED;
1806 POHCI_HCD_ED PreviousED;
1807 POHCI_STATIC_ED HeadED;
1808
1809 DPRINT_OHCI("OHCI_RemoveEndpointFromSchedule \n");
1810
1811 ED = OhciEndpoint->HcdED;
1812 HeadED = OhciEndpoint->HeadED;
1813
1814 if (&HeadED->Link == ED->HcdEDLink.Blink)
1815 {
1816 if (HeadED->Type == OHCI_STATIC_ED_TYPE_CONTROL ||
1817 HeadED->Type == OHCI_STATIC_ED_TYPE_BULK)
1818 {
1819 WRITE_REGISTER_ULONG(HeadED->pNextED, ED->HwED.NextED);
1820 }
1821 else if (HeadED->Type == OHCI_STATIC_ED_TYPE_INTERRUPT)
1822 {
1823 *HeadED->pNextED = ED->HwED.NextED;
1824 }
1825 else
1826 {
1827 DPRINT1("OHCI_RemoveEndpointFromSchedule: Unknown HeadED->Type - %x\n",
1828 HeadED->Type);
1829 DbgBreakPoint();
1830 }
1831 }
1832 else
1833 {
1834 PreviousED = CONTAINING_RECORD(ED->HcdEDLink.Blink,
1835 OHCI_HCD_ED,
1836 HcdEDLink);
1837
1838 PreviousED->HwED.NextED = ED->HwED.NextED;
1839 }
1840
1841 RemoveEntryList(&ED->HcdEDLink);
1842
1843 OhciEndpoint->HeadED = NULL;
1844 }
1845
1846 VOID
1847 NTAPI
1848 OHCI_SetEndpointState(IN PVOID ohciExtension,
1849 IN PVOID ohciEndpoint,
1850 IN ULONG EndpointState)
1851 {
1852 POHCI_EXTENSION OhciExtension = ohciExtension;
1853 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1854 POHCI_HCD_ED ED;
1855
1856 DPRINT_OHCI("OHCI_SetEndpointState: EndpointState - %x\n",
1857 EndpointState);
1858
1859 ED = OhciEndpoint->HcdED;
1860
1861 switch (EndpointState)
1862 {
1863 case USBPORT_ENDPOINT_PAUSED:
1864 ED->HwED.EndpointControl.sKip = 1;
1865 break;
1866
1867 case USBPORT_ENDPOINT_ACTIVE:
1868 ED->HwED.EndpointControl.sKip = 0;
1869 OHCI_EnableList(OhciExtension, OhciEndpoint);
1870 break;
1871
1872 case USBPORT_ENDPOINT_REMOVE:
1873 ED->HwED.EndpointControl.sKip = 1;
1874 ED->Flags |= OHCI_HCD_ED_FLAG_NOT_ACCESSED;
1875 OHCI_RemoveEndpointFromSchedule(OhciEndpoint);
1876 break;
1877
1878 default:
1879 ASSERT(FALSE);
1880 break;
1881 }
1882 }
1883
1884 VOID
1885 NTAPI
1886 OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension,
1887 IN POHCI_ENDPOINT OhciEndpoint)
1888 {
1889 PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1890 POHCI_HCD_ED ED;
1891 ULONG_PTR NextTdPA;
1892 POHCI_HCD_TD NextTD;
1893 POHCI_HCD_TD TD;
1894 PLIST_ENTRY DoneList;
1895 POHCI_TRANSFER OhciTransfer;
1896 POHCI_HCD_TD ControlStatusTD;
1897 ULONG_PTR PhysicalAddress;
1898 ULONG TransferNumber;
1899 POHCI_TRANSFER transfer;
1900 UCHAR ConditionCode;
1901 BOOLEAN IsResetOnHalt = FALSE;
1902
1903 //DPRINT_OHCI("OHCI_PollAsyncEndpoint: Endpoint - %p\n", OhciEndpoint);
1904
1905 ED = OhciEndpoint->HcdED;
1906 NextTdPA = ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK;
1907
1908 if (!NextTdPA)
1909 {
1910 OHCI_DumpHcdED(ED);
1911 DbgBreakPoint();
1912 }
1913
1914 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA,
1915 OhciExtension,
1916 OhciEndpoint);
1917 DPRINT_OHCI("NextTD - %p\n", NextTD);
1918
1919 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) == 0)
1920 goto ProcessListTDs;
1921
1922 OHCI_DumpHcdED(ED);
1923
1924 IsResetOnHalt = (ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT) != 0;
1925 DPRINT1("PollAsyncEndpoint: IsResetOnHalt %x\n", IsResetOnHalt);
1926
1927 for (TD = OhciEndpoint->HcdHeadP; ; TD = TD->NextTDVa)
1928 {
1929 if (!TD)
1930 {
1931 OHCI_DumpHcdED(ED);
1932 DbgBreakPoint();
1933 }
1934
1935 if (TD == NextTD)
1936 {
1937 DPRINT("TD == NextTD - %p\n", TD);
1938 goto HandleDoneList;
1939 }
1940
1941 OhciTransfer = TD->OhciTransfer;
1942 ConditionCode = TD->HwTD.gTD.Control.ConditionCode;
1943
1944 DPRINT("TD - %p, ConditionCode - %X\n", TD, ConditionCode);
1945 OHCI_DumpHcdTD(TD);
1946
1947 switch (ConditionCode)
1948 {
1949 case OHCI_TD_CONDITION_NO_ERROR:
1950 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
1951 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1952 continue;
1953
1954 case OHCI_TD_CONDITION_NOT_ACCESSED:
1955 TD->Flags |= (OHCI_HCD_TD_FLAG_DONE | OHCI_HCD_TD_FLAG_NOT_ACCESSED);
1956 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1957 continue;
1958
1959 case OHCI_TD_CONDITION_DATA_UNDERRUN:
1960 DPRINT1("DATA_UNDERRUN. Transfer->Flags - %X\n", OhciTransfer->Flags);
1961
1962 if (OhciTransfer->Flags & OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK)
1963 {
1964 IsResetOnHalt = TRUE;
1965 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
1966
1967 ControlStatusTD = OhciTransfer->ControlStatusTD;
1968
1969 if ((TD->Flags & OHCI_HCD_TD_FLAG_CONTROL_STATUS) == 0 &&
1970 ControlStatusTD)
1971 {
1972 PhysicalAddress = ControlStatusTD->PhysicalAddress;
1973 PhysicalAddress |= (ED->HwED.HeadPointer &
1974 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
1975
1976 ED->HwED.HeadPointer = PhysicalAddress;
1977
1978 NextTD = OhciTransfer->ControlStatusTD;
1979 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
1980 }
1981 else
1982 {
1983 TransferParameters = OhciTransfer->TransferParameters;
1984
1985 if (TransferParameters->IsTransferSplited)
1986 {
1987 TransferNumber = TransferParameters->TransferCounter;
1988 transfer = OhciTransfer;
1989
1990 do
1991 {
1992 transfer = transfer->NextTD->OhciTransfer;
1993 NextTD = transfer->NextTD;
1994 }
1995 while (transfer && TransferNumber ==
1996 transfer->TransferParameters->TransferCounter);
1997
1998 PhysicalAddress = NextTD->PhysicalAddress;
1999 PhysicalAddress |= (ED->HwED.HeadPointer &
2000 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2001
2002 ED->HwED.HeadPointer = PhysicalAddress;
2003 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2004 }
2005 else
2006 {
2007 PhysicalAddress = OhciTransfer->NextTD->PhysicalAddress;
2008 PhysicalAddress |= (ED->HwED.HeadPointer &
2009 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2010
2011 ED->HwED.HeadPointer = PhysicalAddress;
2012
2013 NextTD = OhciTransfer->NextTD;
2014 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2015 }
2016 }
2017
2018 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2019 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2020 continue;
2021 }
2022
2023 /* fall through */
2024
2025 default:
2026 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2027 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2028
2029 ED->HwED.HeadPointer = OhciTransfer->NextTD->PhysicalAddress |
2030 (ED->HwED.HeadPointer &
2031 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2032
2033 NextTD = OhciTransfer->NextTD;
2034 break;
2035 }
2036 }
2037
2038 ProcessListTDs:
2039
2040 TD = OhciEndpoint->HcdHeadP;
2041
2042 while (TD != NextTD)
2043 {
2044 OHCI_DumpHcdTD(TD);
2045 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2046 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2047 TD = TD->NextTDVa;
2048 }
2049
2050 HandleDoneList:
2051
2052 TD = NextTD;
2053 OhciEndpoint->HcdHeadP = NextTD;
2054
2055 DoneList = &OhciEndpoint->TDList;
2056
2057 while (!IsListEmpty(DoneList))
2058 {
2059 TD = CONTAINING_RECORD(DoneList->Flink,
2060 OHCI_HCD_TD,
2061 DoneLink);
2062
2063 RemoveHeadList(DoneList);
2064
2065 if (TD->Flags & OHCI_HCD_TD_FLAG_DONE &&
2066 TD->Flags & OHCI_HCD_TD_FLAG_PROCESSED)
2067 {
2068 OHCI_ProcessDoneTD(OhciExtension, TD, TRUE);
2069 }
2070 }
2071
2072 if (IsResetOnHalt)
2073 {
2074 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2075 DPRINT("ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer);
2076 }
2077 }
2078
2079 VOID
2080 NTAPI
2081 OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension,
2082 IN POHCI_ENDPOINT OhciEndpoint)
2083 {
2084 DPRINT1("OHCI_PollAsyncEndpoint: UNIMPLEMENTED. FIXME \n");
2085 ASSERT(FALSE);
2086 }
2087
2088 VOID
2089 NTAPI
2090 OHCI_PollEndpoint(IN PVOID ohciExtension,
2091 IN PVOID ohciEndpoint)
2092 {
2093 POHCI_EXTENSION OhciExtension = ohciExtension;
2094 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2095 ULONG TransferType;
2096
2097 DPRINT_OHCI("OHCI_PollEndpoint: OhciExtension - %p, Endpoint - %p\n",
2098 OhciExtension,
2099 OhciEndpoint);
2100
2101 TransferType = OhciEndpoint->EndpointProperties.TransferType;
2102
2103 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2104 {
2105 OHCI_PollIsoEndpoint(OhciExtension, OhciEndpoint);
2106 return;
2107 }
2108
2109 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2110 TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2111 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2112 {
2113 OHCI_PollAsyncEndpoint(OhciExtension, OhciEndpoint);
2114 }
2115 }
2116
2117 VOID
2118 NTAPI
2119 OHCI_CheckController(IN PVOID ohciExtension)
2120 {
2121 POHCI_EXTENSION OhciExtension = ohciExtension;
2122 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2123 PULONG HcControlReg;
2124 OHCI_REG_CONTROL HcControl;
2125 ULONG FmNumber;
2126 USHORT FmDiff;
2127 POHCI_HCCA HcHCCA;
2128
2129 //DPRINT_OHCI("OHCI_CheckController: ...\n");
2130
2131 OperationalRegs = OhciExtension->OperationalRegs;
2132
2133 if (!OHCI_HardwarePresent(OhciExtension, TRUE))
2134 return;
2135
2136 HcControlReg = (PULONG)&OperationalRegs->HcControl;
2137 HcControl.AsULONG = READ_REGISTER_ULONG(HcControlReg);
2138
2139 if (HcControl.HostControllerFunctionalState != OHCI_HC_STATE_OPERATIONAL)
2140 return;
2141
2142 FmNumber = READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber);
2143 FmDiff = (USHORT)(FmNumber - OhciExtension->HcdFmNumber);
2144
2145 if (FmNumber == 0 || FmDiff < 5)
2146 return;
2147
2148 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2149 OhciExtension->HcdFmNumber = FmNumber;
2150
2151 if (HcHCCA->Pad1 == 0)
2152 {
2153 HcHCCA->Pad1 = 0xBAD1;
2154 return;
2155 }
2156
2157 DPRINT1("OHCI_CheckController: HcHCCA->Pad1 - %x\n", HcHCCA->Pad1);
2158
2159 if (HcHCCA->Pad1 == 0xBAD1)
2160 {
2161 HcHCCA->Pad1 = 0xBAD2;
2162 }
2163 else if (HcHCCA->Pad1 == 0xBAD2)
2164 {
2165 HcHCCA->Pad1 = 0xBAD3;
2166
2167 RegPacket.UsbPortInvalidateController(OhciExtension,
2168 USBPORT_INVALIDATE_CONTROLLER_RESET);
2169 }
2170 }
2171
2172 ULONG
2173 NTAPI
2174 OHCI_Get32BitFrameNumber(IN PVOID ohciExtension)
2175 {
2176 POHCI_EXTENSION OhciExtension = ohciExtension;
2177 POHCI_HCCA HcHCCA;
2178 ULONG fm;
2179 ULONG hp;
2180
2181 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2182
2183 /* 5.4 FrameInterval Counter: Get32BitFrameNumber() */
2184
2185 hp = OhciExtension->FrameHighPart;
2186 fm = HcHCCA->FrameNumber;
2187
2188 DPRINT_OHCI("OHCI_Get32BitFrameNumber: hp - %lX, fm - %lX\n", hp, fm);
2189
2190 return ((fm & 0x7FFF) | hp) + ((fm ^ hp) & 0x8000);
2191 }
2192
2193 VOID
2194 NTAPI
2195 OHCI_InterruptNextSOF(IN PVOID ohciExtension)
2196 {
2197 POHCI_EXTENSION OhciExtension = ohciExtension;
2198 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2199 PULONG InterruptEnableReg;
2200 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2201
2202 DPRINT_OHCI("OHCI_InterruptNextSOF: OhciExtension - %p\n",
2203 OhciExtension);
2204
2205 OperationalRegs = OhciExtension->OperationalRegs;
2206 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2207
2208 /* Enable interrupt generation due to Start of Frame */
2209 IntEnable.AsULONG = 0;
2210 IntEnable.StartofFrame = 1;
2211
2212 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2213 }
2214
2215 VOID
2216 NTAPI
2217 OHCI_EnableInterrupts(IN PVOID ohciExtension)
2218 {
2219 POHCI_EXTENSION OhciExtension = ohciExtension;
2220 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2221 PULONG InterruptEnableReg;
2222 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2223
2224 DPRINT_OHCI("OHCI_EnableInterrupts: OhciExtension - %p\n",
2225 OhciExtension);
2226
2227 OperationalRegs = OhciExtension->OperationalRegs;
2228 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2229
2230 /* Enable interrupt generation */
2231 IntEnable.AsULONG = 0;
2232 IntEnable.MasterInterruptEnable = 1;
2233
2234 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2235 }
2236
2237 VOID
2238 NTAPI
2239 OHCI_DisableInterrupts(IN PVOID ohciExtension)
2240 {
2241 POHCI_EXTENSION OhciExtension = ohciExtension;
2242 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2243 PULONG InterruptDisableReg;
2244 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
2245
2246 DPRINT_OHCI("OHCI_DisableInterrupts\n");
2247
2248 OperationalRegs = OhciExtension->OperationalRegs;
2249 InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
2250
2251 /* Disable interrupt generation */
2252 IntDisable.AsULONG = 0;
2253 IntDisable.MasterInterruptEnable = 1;
2254
2255 WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
2256 }
2257
2258 VOID
2259 NTAPI
2260 OHCI_PollController(IN PVOID ohciExtension)
2261 {
2262 DPRINT1("OHCI_PollController: UNIMPLEMENTED. FIXME\n");
2263 }
2264
2265 VOID
2266 NTAPI
2267 OHCI_SetEndpointDataToggle(IN PVOID ohciExtension,
2268 IN PVOID ohciEndpoint,
2269 IN ULONG DataToggle)
2270 {
2271 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2272 POHCI_HCD_ED ED;
2273
2274 DPRINT_OHCI("OHCI_SetEndpointDataToggle: Endpoint - %p, DataToggle - %x\n",
2275 OhciEndpoint,
2276 DataToggle);
2277
2278 ED = OhciEndpoint->HcdED;
2279
2280 if (DataToggle)
2281 ED->HwED.HeadPointer |= OHCI_ED_HEAD_POINTER_CARRY;
2282 else
2283 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_CARRY;
2284 }
2285
2286 ULONG
2287 NTAPI
2288 OHCI_GetEndpointStatus(IN PVOID ohciExtension,
2289 IN PVOID ohciEndpoint)
2290 {
2291 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2292 POHCI_HCD_ED ED;
2293 ULONG EndpointStatus = USBPORT_ENDPOINT_RUN;
2294
2295 DPRINT_OHCI("OHCI_GetEndpointStatus: ... \n");
2296
2297 ED = OhciEndpoint->HcdED;
2298
2299 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) &&
2300 !(ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT))
2301 {
2302 EndpointStatus = USBPORT_ENDPOINT_HALT;
2303 }
2304
2305 return EndpointStatus;
2306 }
2307
2308 VOID
2309 NTAPI
2310 OHCI_SetEndpointStatus(IN PVOID ohciExtension,
2311 IN PVOID ohciEndpoint,
2312 IN ULONG EndpointStatus)
2313 {
2314 POHCI_EXTENSION OhciExtension = ohciExtension;
2315 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2316 POHCI_HCD_ED ED;
2317
2318 DPRINT_OHCI("OHCI_SetEndpointStatus: Endpoint - %p, EndpointStatus - %lX\n",
2319 OhciEndpoint,
2320 EndpointStatus);
2321
2322 if (EndpointStatus == USBPORT_ENDPOINT_RUN)
2323 {
2324 ED = OhciEndpoint->HcdED;
2325 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2326
2327 OHCI_EnableList(OhciExtension, OhciEndpoint);
2328 }
2329 else if (EndpointStatus == USBPORT_ENDPOINT_HALT)
2330 {
2331 ASSERT(FALSE);
2332 }
2333 }
2334
2335 VOID
2336 NTAPI
2337 OHCI_ResetController(IN PVOID ohciExtension)
2338 {
2339 POHCI_EXTENSION OhciExtension = ohciExtension;
2340 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2341 ULONG FrameNumber;
2342 PULONG ControlReg;
2343 PULONG CommandStatusReg;
2344 PULONG InterruptEnableReg;
2345 PULONG FmIntervalReg;
2346 PULONG RhStatusReg;
2347 PULONG PortStatusReg;
2348 OHCI_REG_CONTROL ControlBak;
2349 OHCI_REG_CONTROL Control;
2350 OHCI_REG_COMMAND_STATUS CommandStatus;
2351 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2352 ULONG_PTR HCCA;
2353 ULONG_PTR ControlHeadED;
2354 ULONG_PTR BulkHeadED;
2355 OHCI_REG_FRAME_INTERVAL FrameInterval;
2356 ULONG_PTR PeriodicStart;
2357 ULONG_PTR LSThreshold;
2358 OHCI_REG_RH_STATUS RhStatus;
2359 OHCI_REG_RH_DESCRIPTORA RhDescriptorA;
2360 OHCI_REG_RH_PORT_STATUS PortStatus;
2361 ULONG NumPorts;
2362 ULONG ix;
2363
2364 DPRINT("OHCI_ResetController: ... \n");
2365
2366 OperationalRegs = OhciExtension->OperationalRegs;
2367
2368 ControlReg = (PULONG)&OperationalRegs->HcControl;
2369 CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
2370 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2371 FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
2372 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
2373
2374 /* Backup FrameNumber from HcHCCA */
2375 FrameNumber = OhciExtension->HcResourcesVA->HcHCCA.FrameNumber;
2376
2377 /* Backup registers */
2378 ControlBak.AsULONG = READ_REGISTER_ULONG(ControlReg);
2379 HCCA = READ_REGISTER_ULONG(&OperationalRegs->HcHCCA);
2380 ControlHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcControlHeadED);
2381 BulkHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED);
2382 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
2383 PeriodicStart = READ_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart);
2384 LSThreshold = READ_REGISTER_ULONG(&OperationalRegs->HcLSThreshold);
2385
2386 /* Reset HostController */
2387 CommandStatus.AsULONG = 0;
2388 CommandStatus.HostControllerReset = 1;
2389 WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
2390
2391 KeStallExecutionProcessor(10);
2392
2393 /* Restore registers */
2394 WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA, HCCA);
2395 WRITE_REGISTER_ULONG(&OperationalRegs->HcControlHeadED, ControlHeadED);
2396 WRITE_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED, BulkHeadED);
2397
2398 /* Set OPERATIONAL state for HC */
2399 Control.AsULONG = 0;
2400 Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2401 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
2402
2403 /* Set Toggle bit for FmInterval register */
2404 FrameInterval.FrameIntervalToggle = 1;
2405 WRITE_REGISTER_ULONG(FmIntervalReg, FrameInterval.AsULONG);
2406
2407 /* Restore registers */
2408 WRITE_REGISTER_ULONG(&OperationalRegs->HcFmNumber, FrameNumber);
2409 WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart, PeriodicStart);
2410 WRITE_REGISTER_ULONG(&OperationalRegs->HcLSThreshold, LSThreshold);
2411
2412 /* Setup RhStatus register */
2413 RhStatus.AsULONG = 0;
2414 RhStatus.SetRemoteWakeupEnable = 1;
2415 RhStatus.SetGlobalPower = 1;
2416 WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
2417
2418 /* Setup RH PortStatus registers */
2419 RhDescriptorA = OHCI_ReadRhDescriptorA(OhciExtension);
2420 NumPorts = RhDescriptorA.NumberDownstreamPorts;
2421
2422 PortStatus.AsULONG = 0;
2423 PortStatus.SetPortPower = 1;
2424
2425 for (ix = 0; ix < NumPorts; ix++)
2426 {
2427 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[ix];
2428 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG);
2429 }
2430
2431 /* Restore HcControl register */
2432 ControlBak.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2433 WRITE_REGISTER_ULONG(ControlReg, ControlBak.AsULONG);
2434
2435 /* Setup HcInterruptEnable register */
2436 IntEnable.AsULONG = 0xFFFFFFFF;
2437 IntEnable.Reserved1 = 0;
2438 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2439 }
2440
2441 MPSTATUS
2442 NTAPI
2443 OHCI_StartSendOnePacket(IN PVOID ohciExtension,
2444 IN PVOID PacketParameters,
2445 IN PVOID Data,
2446 IN PULONG pDataLength,
2447 IN PVOID BufferVA,
2448 IN PVOID BufferPA,
2449 IN ULONG BufferLength,
2450 IN USBD_STATUS * pUSBDStatus)
2451 {
2452 DPRINT1("OHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n");
2453 return MP_STATUS_SUCCESS;
2454 }
2455
2456 MPSTATUS
2457 NTAPI
2458 OHCI_EndSendOnePacket(IN PVOID ohciExtension,
2459 IN PVOID PacketParameters,
2460 IN PVOID Data,
2461 IN PULONG pDataLength,
2462 IN PVOID BufferVA,
2463 IN PVOID BufferPA,
2464 IN ULONG BufferLength,
2465 IN USBD_STATUS * pUSBDStatus)
2466 {
2467 DPRINT1("OHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n");
2468 return MP_STATUS_SUCCESS;
2469 }
2470
2471 MPSTATUS
2472 NTAPI
2473 OHCI_PassThru(IN PVOID ohciExtension,
2474 IN PVOID passThruParameters,
2475 IN ULONG ParameterLength,
2476 IN PVOID pParameters)
2477 {
2478 DPRINT1("OHCI_PassThru: UNIMPLEMENTED. FIXME\n");
2479 return MP_STATUS_SUCCESS;
2480 }
2481
2482 VOID
2483 NTAPI
2484 OHCI_Unload(IN PDRIVER_OBJECT DriverObject)
2485 {
2486 #if DBG
2487 DPRINT1("OHCI_Unload: Not supported\n");
2488 #endif
2489 return;
2490 }
2491
2492 VOID
2493 NTAPI
2494 OHCI_FlushInterrupts(IN PVOID uhciExtension)
2495 {
2496 #if DBG
2497 DPRINT1("OHCI_FlushInterrupts: Not supported\n");
2498 #endif
2499 return;
2500 }
2501
2502 NTSTATUS
2503 NTAPI
2504 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2505 IN PUNICODE_STRING RegistryPath)
2506 {
2507 NTSTATUS Status;
2508
2509 DPRINT_OHCI("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n",
2510 DriverObject,
2511 RegistryPath);
2512
2513 RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET));
2514
2515 RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_OHCI;
2516
2517 RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT |
2518 USB_MINIPORT_FLAGS_MEMORY_IO;
2519
2520 RegPacket.MiniPortBusBandwidth = TOTAL_USB11_BUS_BANDWIDTH;
2521
2522 RegPacket.MiniPortExtensionSize = sizeof(OHCI_EXTENSION);
2523 RegPacket.MiniPortEndpointSize = sizeof(OHCI_ENDPOINT);
2524 RegPacket.MiniPortTransferSize = sizeof(OHCI_TRANSFER);
2525 RegPacket.MiniPortResourcesSize = sizeof(OHCI_HC_RESOURCES);
2526
2527 RegPacket.OpenEndpoint = OHCI_OpenEndpoint;
2528 RegPacket.ReopenEndpoint = OHCI_ReopenEndpoint;
2529 RegPacket.QueryEndpointRequirements = OHCI_QueryEndpointRequirements;
2530 RegPacket.CloseEndpoint = OHCI_CloseEndpoint;
2531 RegPacket.StartController = OHCI_StartController;
2532 RegPacket.StopController = OHCI_StopController;
2533 RegPacket.SuspendController = OHCI_SuspendController;
2534 RegPacket.ResumeController = OHCI_ResumeController;
2535 RegPacket.InterruptService = OHCI_InterruptService;
2536 RegPacket.InterruptDpc = OHCI_InterruptDpc;
2537 RegPacket.SubmitTransfer = OHCI_SubmitTransfer;
2538 RegPacket.SubmitIsoTransfer = OHCI_SubmitIsoTransfer;
2539 RegPacket.AbortTransfer = OHCI_AbortTransfer;
2540 RegPacket.GetEndpointState = OHCI_GetEndpointState;
2541 RegPacket.SetEndpointState = OHCI_SetEndpointState;
2542 RegPacket.PollEndpoint = OHCI_PollEndpoint;
2543 RegPacket.CheckController = OHCI_CheckController;
2544 RegPacket.Get32BitFrameNumber = OHCI_Get32BitFrameNumber;
2545 RegPacket.InterruptNextSOF = OHCI_InterruptNextSOF;
2546 RegPacket.EnableInterrupts = OHCI_EnableInterrupts;
2547 RegPacket.DisableInterrupts = OHCI_DisableInterrupts;
2548 RegPacket.PollController = OHCI_PollController;
2549 RegPacket.SetEndpointDataToggle = OHCI_SetEndpointDataToggle;
2550 RegPacket.GetEndpointStatus = OHCI_GetEndpointStatus;
2551 RegPacket.SetEndpointStatus = OHCI_SetEndpointStatus;
2552 RegPacket.ResetController = OHCI_ResetController;
2553 RegPacket.RH_GetRootHubData = OHCI_RH_GetRootHubData;
2554 RegPacket.RH_GetStatus = OHCI_RH_GetStatus;
2555 RegPacket.RH_GetPortStatus = OHCI_RH_GetPortStatus;
2556 RegPacket.RH_GetHubStatus = OHCI_RH_GetHubStatus;
2557 RegPacket.RH_SetFeaturePortReset = OHCI_RH_SetFeaturePortReset;
2558 RegPacket.RH_SetFeaturePortPower = OHCI_RH_SetFeaturePortPower;
2559 RegPacket.RH_SetFeaturePortEnable = OHCI_RH_SetFeaturePortEnable;
2560 RegPacket.RH_SetFeaturePortSuspend = OHCI_RH_SetFeaturePortSuspend;
2561 RegPacket.RH_ClearFeaturePortEnable = OHCI_RH_ClearFeaturePortEnable;
2562 RegPacket.RH_ClearFeaturePortPower = OHCI_RH_ClearFeaturePortPower;
2563 RegPacket.RH_ClearFeaturePortSuspend = OHCI_RH_ClearFeaturePortSuspend;
2564 RegPacket.RH_ClearFeaturePortEnableChange = OHCI_RH_ClearFeaturePortEnableChange;
2565 RegPacket.RH_ClearFeaturePortConnectChange = OHCI_RH_ClearFeaturePortConnectChange;
2566 RegPacket.RH_ClearFeaturePortResetChange = OHCI_RH_ClearFeaturePortResetChange;
2567 RegPacket.RH_ClearFeaturePortSuspendChange = OHCI_RH_ClearFeaturePortSuspendChange;
2568 RegPacket.RH_ClearFeaturePortOvercurrentChange = OHCI_RH_ClearFeaturePortOvercurrentChange;
2569 RegPacket.RH_DisableIrq = OHCI_RH_DisableIrq;
2570 RegPacket.RH_EnableIrq = OHCI_RH_EnableIrq;
2571 RegPacket.StartSendOnePacket = OHCI_StartSendOnePacket;
2572 RegPacket.EndSendOnePacket = OHCI_EndSendOnePacket;
2573 RegPacket.PassThru = OHCI_PassThru;
2574 RegPacket.FlushInterrupts = OHCI_FlushInterrupts;
2575
2576 DriverObject->DriverUnload = OHCI_Unload;
2577
2578 Status = USBPORT_RegisterUSBPortDriver(DriverObject,
2579 USB10_MINIPORT_INTERFACE_VERSION,
2580 &RegPacket);
2581
2582 DPRINT_OHCI("DriverEntry: USBPORT_RegisterUSBPortDriver return Status - %x\n",
2583 Status);
2584
2585 return Status;
2586 }