[USBOHCI_NEW] Simplify the MapTransferToTD routine and add some docs
[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("NextHcdTD - %08X\n", TD->NextHcdTD);
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 return TD;
1250 }
1251
1252 ULONG
1253 NTAPI
1254 OHCI_RemainTDs(IN POHCI_EXTENSION OhciExtension,
1255 IN POHCI_ENDPOINT OhciEndpoint)
1256 {
1257 POHCI_HCD_TD TD;
1258 ULONG MaxTDs;
1259 ULONG RemainTDs;
1260 ULONG ix;
1261
1262 DPRINT_OHCI("OHCI_RemainTDs: ... \n");
1263
1264 MaxTDs = OhciEndpoint->MaxTransferDescriptors;
1265 TD = OhciEndpoint->FirstTD;
1266
1267 RemainTDs = 0;
1268
1269 for (ix = 0; ix < MaxTDs; ix++)
1270 {
1271 if (!(TD->Flags & OHCI_HCD_TD_FLAG_ALLOCATED))
1272 RemainTDs++;
1273
1274 TD += 1;
1275 }
1276
1277 return RemainTDs;
1278 }
1279
1280 MPSTATUS
1281 NTAPI
1282 OHCI_ControlTransfer(IN POHCI_EXTENSION OhciExtension,
1283 IN POHCI_ENDPOINT OhciEndpoint,
1284 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1285 IN POHCI_TRANSFER OhciTransfer,
1286 IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1287 {
1288 POHCI_HCD_TD FirstTD;
1289 ULONG FirstTdPA;
1290 POHCI_HCD_TD TD;
1291 POHCI_HCD_TD TD2;
1292 POHCI_HCD_TD PrevTD;
1293 POHCI_HCD_TD NextTD;
1294 ULONG MaxTDs;
1295 ULONG TransferedLen;
1296 ULONG BufferEnd;
1297 UCHAR DataToggle;
1298
1299 DPRINT_OHCI("OHCI_ControlTransfer: Ext %p, Endpoint %p\n",
1300 OhciExtension,
1301 OhciEndpoint);
1302
1303 MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint);
1304
1305 if ((SGList->SgElementCount + OHCI_NON_DATA_CONTROL_TDS) > MaxTDs)
1306 return MP_STATUS_FAILURE;
1307
1308 FirstTD = OhciEndpoint->HcdTailP;
1309 FirstTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1310
1311 FirstTD->HwTD.gTD.NextTD = 0;
1312 FirstTD->HwTD.gTD.CurrentBuffer = 0;
1313 FirstTD->HwTD.gTD.BufferEnd = 0;
1314
1315 FirstTD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1316 FirstTD->NextHcdTD = 0;
1317 FirstTD->OhciTransfer = OhciTransfer;
1318
1319 FirstTD->HwTD.Padded[0] = 0;
1320 FirstTD->HwTD.Padded[1] = 0;
1321
1322 OhciTransfer->PendingTDs++;
1323
1324 RtlCopyMemory(&FirstTD->HwTD.SetupPacket,
1325 &TransferParameters->SetupPacket,
1326 sizeof(FirstTD->HwTD.SetupPacket));
1327
1328 FirstTdPA = FirstTD->PhysicalAddress;
1329
1330 FirstTD->HwTD.gTD.CurrentBuffer = FirstTdPA + FIELD_OFFSET(OHCI_HCD_TD, HwTD.SetupPacket);
1331
1332 BufferEnd = FirstTdPA + FIELD_OFFSET(OHCI_HCD_TD, HwTD.SetupPacket) +
1333 sizeof(USB_DEFAULT_PIPE_SETUP_PACKET) - 1;
1334
1335 FirstTD->HwTD.gTD.BufferEnd = BufferEnd;
1336
1337 FirstTD->HwTD.gTD.Control.AsULONG = 0;
1338 FirstTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1339 FirstTD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1340 FirstTD->HwTD.gTD.Control.DataToggle = OHCI_TD_DATA_TOGGLE_DATA0;
1341
1342 TD2 = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1343
1344 TD2->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1345 TD2->HwTD.gTD.CurrentBuffer = 0;
1346 TD2->HwTD.gTD.BufferEnd = 0;
1347 TD2->HwTD.gTD.NextTD = 0;
1348
1349 TD2->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1350 TD2->NextHcdTD = 0;
1351 TD2->OhciTransfer = OhciTransfer;
1352
1353 RtlZeroMemory(&TD2->HwTD.SetupPacket,
1354 sizeof(TD2->HwTD.SetupPacket));
1355
1356 TD2->HwTD.Padded[0] = 0;
1357 TD2->HwTD.Padded[1] = 0;
1358
1359 PrevTD = FirstTD;
1360 TD = TD2;
1361
1362 PrevTD->HwTD.gTD.NextTD = TD2->PhysicalAddress;
1363 PrevTD->NextHcdTD = TD2;
1364
1365 TransferedLen = 0;
1366 DataToggle = OHCI_TD_DATA_TOGGLE_DATA1;
1367
1368 while (TransferedLen < TransferParameters->TransferBufferLength)
1369 {
1370 OhciTransfer->PendingTDs++;
1371
1372 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
1373 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1374 else
1375 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1376
1377 TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1378 TD->HwTD.gTD.Control.DataToggle = DataToggle;
1379 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1380
1381 DataToggle = OHCI_TD_DATA_TOGGLE_FROM_ED;
1382
1383 TransferedLen = OHCI_MapTransferToTD(OhciExtension,
1384 TransferedLen,
1385 OhciTransfer,
1386 TD,
1387 SGList);
1388
1389 PrevTD = TD;
1390
1391 TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1392
1393 TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1394
1395 TD->HwTD.gTD.NextTD = 0;
1396 TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1397
1398 TD->NextHcdTD = 0;
1399 TD->OhciTransfer = OhciTransfer;
1400
1401 TD->HwTD.gTD.CurrentBuffer = 0;
1402 TD->HwTD.gTD.BufferEnd = 0;
1403
1404 RtlZeroMemory(&TD->HwTD.SetupPacket,
1405 sizeof(TD->HwTD.SetupPacket));
1406
1407 TD->HwTD.Padded[0] = 0;
1408 TD->HwTD.Padded[1] = 0;
1409
1410 PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1411 PrevTD->NextHcdTD = TD;
1412 }
1413
1414 if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK)
1415 {
1416 PrevTD->HwTD.gTD.Control.BufferRounding = TRUE;
1417 OhciTransfer->Flags |= OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK;
1418 }
1419
1420 TD->HwTD.gTD.CurrentBuffer = 0;
1421 TD->HwTD.gTD.BufferEnd = 0;
1422
1423 TD->Flags |= OHCI_HCD_TD_FLAG_CONTROL_STATUS;
1424 TD->TransferLen = 0;
1425
1426 TD->HwTD.gTD.Control.AsULONG = 0;
1427
1428 if ((TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) != 0)
1429 {
1430 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1431 }
1432 else
1433 {
1434 TD->HwTD.gTD.Control.BufferRounding = TRUE;
1435 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1436 }
1437
1438 TD->HwTD.gTD.Control.DataToggle = OHCI_TD_DATA_TOGGLE_DATA1;
1439 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1440
1441 OhciTransfer->PendingTDs++;
1442 OhciTransfer->ControlStatusTD = TD;
1443
1444 NextTD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1445
1446 TD->HwTD.gTD.NextTD = NextTD->PhysicalAddress;
1447 TD->NextHcdTD = NextTD;
1448
1449 NextTD->NextHcdTD = 0;
1450 NextTD->HwTD.gTD.NextTD = 0;
1451
1452 OhciTransfer->NextTD = NextTD;
1453 OhciEndpoint->HcdTailP = NextTD;
1454
1455 OhciEndpoint->HcdED->HwED.TailPointer = NextTD->PhysicalAddress;
1456
1457 OHCI_EnableList(OhciExtension, OhciEndpoint);
1458
1459 return MP_STATUS_SUCCESS;
1460 }
1461
1462 /**
1463 * @brief Creates the transfer descriptor chain for the given transfer's buffer
1464 * and attaches it to a given endpoint (for bulk or interrupt transfers)
1465 *
1466 * @param[in] OhciExtension The ohci extension
1467 * @param[in] OhciEndpoint The ohci endpoint
1468 * @param[in] TransferParameters The transfer parameters
1469 * @param[in] OhciTransfer The ohci transfer
1470 * @param[in] SGList The scatter/gather list
1471 *
1472 * @return MP_STATUS_SUCCESS or MP_STATUS_FAILURE if there are not enough TDs left
1473 */
1474 MPSTATUS
1475 NTAPI
1476 OHCI_BulkOrInterruptTransfer(IN POHCI_EXTENSION OhciExtension,
1477 IN POHCI_ENDPOINT OhciEndpoint,
1478 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1479 IN POHCI_TRANSFER OhciTransfer,
1480 IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1481 {
1482 POHCI_HCD_TD TD;
1483 POHCI_HCD_TD PrevTD;
1484 ULONG TransferedLen;
1485 ULONG MaxTDs;
1486
1487 DPRINT_OHCI("OHCI_BulkOrInterruptTransfer: ... \n");
1488
1489 MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint);
1490
1491 if (SGList->SgElementCount > MaxTDs)
1492 return MP_STATUS_FAILURE;
1493
1494 TD = OhciEndpoint->HcdTailP;
1495
1496 TransferedLen = 0;
1497
1498 do
1499 {
1500 TD->HwTD.gTD.Control.AsULONG = 0;
1501 TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE;
1502 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED;
1503
1504 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
1505 {
1506 TD->HwTD.gTD.Control.BufferRounding = 0;
1507 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN;
1508 }
1509 else
1510 {
1511 TD->HwTD.gTD.Control.BufferRounding = TRUE;
1512 TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT;
1513 }
1514
1515 TD->HwTD.gTD.CurrentBuffer = 0;
1516 TD->HwTD.gTD.NextTD = 0;
1517 TD->HwTD.gTD.BufferEnd = 0;
1518
1519 RtlZeroMemory(&TD->HwTD.SetupPacket,
1520 sizeof(TD->HwTD.SetupPacket));
1521
1522 TD->HwTD.Padded[0] = 0;
1523 TD->HwTD.Padded[1] = 0;
1524
1525 TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED;
1526 TD->OhciTransfer = OhciTransfer;
1527 TD->NextHcdTD = 0;
1528
1529 if (TransferParameters->TransferBufferLength)
1530 {
1531 TransferedLen = OHCI_MapTransferToTD(OhciExtension,
1532 TransferedLen,
1533 OhciTransfer,
1534 TD,
1535 SGList);
1536 }
1537 else
1538 {
1539 ASSERT(SGList->SgElementCount == 0);
1540
1541 TD->HwTD.gTD.CurrentBuffer = 0;
1542 TD->HwTD.gTD.BufferEnd = 0;
1543
1544 TD->TransferLen = 0;
1545 }
1546
1547 PrevTD = TD;
1548
1549 TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint);
1550 OhciTransfer->PendingTDs++;
1551
1552 PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1553 PrevTD->NextHcdTD = TD;
1554 }
1555 while (TransferedLen < TransferParameters->TransferBufferLength);
1556
1557 if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK)
1558 {
1559 PrevTD->HwTD.gTD.Control.BufferRounding = TRUE;
1560 OhciTransfer->Flags |= OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK;
1561 }
1562
1563 PrevTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_IMMEDIATE;
1564 PrevTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1565 PrevTD->NextHcdTD = TD;
1566
1567 /* The last TD in a chain is not used in a transfer. The controller does not access it
1568 * so it will be used for chaining a next transfer to it (OpenHCI spec, 4.6)
1569 */
1570 TD->HwTD.gTD.NextTD = 0;
1571 TD->NextHcdTD = 0;
1572
1573 OhciTransfer->NextTD = TD;
1574 OhciEndpoint->HcdTailP = TD;
1575
1576 OhciEndpoint->HcdED->HwED.TailPointer = TD->PhysicalAddress;
1577
1578 OHCI_EnableList(OhciExtension, OhciEndpoint);
1579
1580 return MP_STATUS_SUCCESS;
1581 }
1582
1583 MPSTATUS
1584 NTAPI
1585 OHCI_SubmitTransfer(IN PVOID ohciExtension,
1586 IN PVOID ohciEndpoint,
1587 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1588 IN PVOID ohciTransfer,
1589 IN PUSBPORT_SCATTER_GATHER_LIST SGList)
1590 {
1591 POHCI_EXTENSION OhciExtension = ohciExtension;
1592 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1593 POHCI_TRANSFER OhciTransfer = ohciTransfer;
1594 ULONG TransferType;
1595
1596 DPRINT_OHCI("OHCI_SubmitTransfer: ... \n");
1597
1598 RtlZeroMemory(OhciTransfer, sizeof(OHCI_TRANSFER));
1599
1600 OhciTransfer->TransferParameters = TransferParameters;
1601 OhciTransfer->OhciEndpoint = OhciEndpoint;
1602
1603 TransferType = OhciEndpoint->EndpointProperties.TransferType;
1604
1605 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
1606 {
1607 return OHCI_ControlTransfer(OhciExtension,
1608 OhciEndpoint,
1609 TransferParameters,
1610 OhciTransfer,
1611 SGList);
1612 }
1613
1614 if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
1615 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1616 {
1617 return OHCI_BulkOrInterruptTransfer(OhciExtension,
1618 OhciEndpoint,
1619 TransferParameters,
1620 OhciTransfer,
1621 SGList);
1622 }
1623
1624 return MP_STATUS_FAILURE;
1625 }
1626
1627 MPSTATUS
1628 NTAPI
1629 OHCI_SubmitIsoTransfer(IN PVOID ohciExtension,
1630 IN PVOID ohciEndpoint,
1631 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1632 IN PVOID ohciTransfer,
1633 IN PVOID isoParameters)
1634 {
1635 DPRINT1("OHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n");
1636 return MP_STATUS_SUCCESS;
1637 }
1638
1639 VOID
1640 NTAPI
1641 OHCI_ProcessDoneTD(IN POHCI_EXTENSION OhciExtension,
1642 IN POHCI_HCD_TD TD,
1643 IN BOOLEAN IsPortComplete)
1644 {
1645 POHCI_TRANSFER OhciTransfer;
1646 POHCI_ENDPOINT OhciEndpoint;
1647 ULONG Buffer;
1648 ULONG BufferEnd;
1649 ULONG Length;
1650
1651 DPRINT_OHCI("OHCI_ProcessDoneTD: ... \n");
1652
1653 OhciTransfer = TD->OhciTransfer;
1654 OhciEndpoint = OhciTransfer->OhciEndpoint;
1655
1656 OhciTransfer->PendingTDs--;
1657
1658 Buffer = TD->HwTD.gTD.CurrentBuffer;
1659 BufferEnd = TD->HwTD.gTD.BufferEnd;
1660
1661 if (TD->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1662 {
1663 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
1664 }
1665 else
1666 {
1667 if (TD->HwTD.gTD.CurrentBuffer)
1668 {
1669 if (TD->TransferLen)
1670 {
1671 Length = (BufferEnd & (PAGE_SIZE - 1)) -
1672 (Buffer & (PAGE_SIZE - 1));
1673
1674 Length++;
1675
1676 if (Buffer >> PAGE_SHIFT != BufferEnd >> PAGE_SHIFT)
1677 Length += PAGE_SIZE;
1678
1679 TD->TransferLen -= Length;
1680 }
1681 }
1682
1683 if (TD->HwTD.gTD.Control.DirectionPID != OHCI_TD_DIRECTION_PID_SETUP)
1684 OhciTransfer->TransferLen += TD->TransferLen;
1685
1686 if (TD->HwTD.gTD.Control.ConditionCode)
1687 {
1688 OhciTransfer->USBDStatus = USBD_STATUS_HALTED |
1689 TD->HwTD.gTD.Control.ConditionCode;
1690 }
1691 }
1692
1693 TD->Flags = 0;
1694 TD->HwTD.gTD.NextTD = 0;
1695 TD->OhciTransfer = 0;
1696
1697 TD->DoneLink.Flink = NULL;
1698 TD->DoneLink.Blink = NULL;
1699
1700 if (IsPortComplete && (OhciTransfer->PendingTDs == 0))
1701 {
1702 RegPacket.UsbPortCompleteTransfer(OhciExtension,
1703 OhciEndpoint,
1704 OhciTransfer->TransferParameters,
1705 OhciTransfer->USBDStatus,
1706 OhciTransfer->TransferLen);
1707 }
1708 }
1709
1710 VOID
1711 NTAPI
1712 OHCI_ProcessDoneIsoTD(IN POHCI_EXTENSION OhciExtension,
1713 IN POHCI_HCD_TD TD,
1714 IN BOOLEAN IsPortComplete)
1715 {
1716 DPRINT1("OHCI_ProcessDoneIsoTD: UNIMPLEMENTED. FIXME\n");
1717 }
1718
1719 VOID
1720 NTAPI
1721 OHCI_AbortTransfer(IN PVOID ohciExtension,
1722 IN PVOID ohciEndpoint,
1723 IN PVOID ohciTransfer,
1724 IN OUT PULONG CompletedLength)
1725 {
1726 POHCI_EXTENSION OhciExtension = ohciExtension;
1727 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1728 POHCI_TRANSFER OhciTransfer = ohciTransfer;
1729 POHCI_TRANSFER TmpTransfer;
1730 POHCI_HCD_ED ED;
1731 ULONG_PTR NextTdPA;
1732 POHCI_HCD_TD NextTD;
1733 POHCI_HCD_TD TD;
1734 POHCI_HCD_TD PrevTD;
1735 POHCI_HCD_TD LastTD;
1736 POHCI_HCD_TD td = NULL;
1737 ULONG ix;
1738 BOOLEAN IsIsoEndpoint = FALSE;
1739 BOOLEAN IsProcessed = FALSE;
1740
1741 DPRINT("OHCI_AbortTransfer: ohciEndpoint - %p, ohciTransfer - %p\n",
1742 OhciEndpoint,
1743 OhciTransfer);
1744
1745 if (OhciEndpoint->EndpointProperties.TransferType ==
1746 USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
1747 {
1748 IsIsoEndpoint = TRUE;
1749 }
1750
1751 ED = OhciEndpoint->HcdED;
1752 NextTdPA = ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK;
1753
1754 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA,
1755 OhciExtension,
1756 OhciEndpoint);
1757
1758 if (NextTD->OhciTransfer == OhciTransfer)
1759 {
1760 LastTD = OhciTransfer->NextTD;
1761
1762 ED->HwED.HeadPointer = LastTD->PhysicalAddress |
1763 (ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_CARRY);
1764
1765 OhciEndpoint->HcdHeadP = LastTD;
1766
1767 for (ix = 0; ix < OhciEndpoint->MaxTransferDescriptors; ix++)
1768 {
1769 TD = &OhciEndpoint->FirstTD[ix];
1770
1771 if (TD->OhciTransfer == OhciTransfer)
1772 {
1773 if (IsIsoEndpoint)
1774 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1775 else
1776 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1777 }
1778 }
1779
1780 *CompletedLength = OhciTransfer->TransferLen;
1781 return;
1782 }
1783
1784 TD = OhciEndpoint->HcdHeadP;
1785
1786 if (TD == NextTD)
1787 goto Exit;
1788
1789 do
1790 {
1791 if (TD->OhciTransfer == ohciTransfer)
1792 {
1793 PrevTD = TD;
1794 TD = TD->NextHcdTD;
1795
1796 if (PrevTD == OhciEndpoint->HcdHeadP)
1797 OhciEndpoint->HcdHeadP = TD;
1798
1799 if (IsIsoEndpoint)
1800 OHCI_ProcessDoneIsoTD(OhciExtension, PrevTD, FALSE);
1801 else
1802 OHCI_ProcessDoneTD(OhciExtension, PrevTD, FALSE);
1803
1804 IsProcessed = TRUE;
1805 }
1806 else
1807 {
1808 TD = TD->NextHcdTD;
1809 }
1810 }
1811 while (TD != NextTD);
1812
1813 if (!IsProcessed)
1814 {
1815 TD = OhciEndpoint->HcdHeadP;
1816
1817 LastTD = TD;
1818 td = NULL;
1819
1820 while (TD != OhciEndpoint->HcdTailP)
1821 {
1822 if (TD->OhciTransfer == OhciTransfer)
1823 {
1824 td = TD;
1825 break;
1826 }
1827
1828 LastTD = TD;
1829
1830 TD = TD->NextHcdTD;
1831 }
1832
1833 TD = td;
1834
1835 do
1836 {
1837 if (TD == OhciEndpoint->HcdTailP)
1838 break;
1839
1840 PrevTD = TD;
1841 TD = TD->NextHcdTD;
1842
1843 if (IsIsoEndpoint)
1844 OHCI_ProcessDoneIsoTD(OhciExtension, PrevTD, FALSE);
1845 else
1846 OHCI_ProcessDoneTD(OhciExtension, PrevTD, FALSE);
1847 }
1848 while (TD->OhciTransfer == OhciTransfer);
1849
1850 TmpTransfer = LastTD->OhciTransfer;
1851 TmpTransfer->NextTD = TD;
1852
1853 LastTD->NextHcdTD = TD;
1854 LastTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1855 }
1856
1857 Exit:
1858
1859 *CompletedLength = OhciTransfer->TransferLen;
1860
1861 if (OhciTransfer->TransferLen)
1862 {
1863 DPRINT("OHCI_AbortTransfer: *CompletedLength - %x\n", *CompletedLength);
1864 }
1865 }
1866
1867 ULONG
1868 NTAPI
1869 OHCI_GetEndpointState(IN PVOID ohciExtension,
1870 IN PVOID ohciEndpoint)
1871 {
1872 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1873 POHCI_HCD_ED ED;
1874
1875 DPRINT_OHCI("OHCI_GetEndpointState: ... \n");
1876
1877 ED = OhciEndpoint->HcdED;
1878
1879 if (ED->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1880 return USBPORT_ENDPOINT_REMOVE;
1881
1882 if (ED->HwED.EndpointControl.sKip)
1883 return USBPORT_ENDPOINT_PAUSED;
1884
1885 return USBPORT_ENDPOINT_ACTIVE;
1886 }
1887
1888 VOID
1889 NTAPI
1890 OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint)
1891 {
1892 POHCI_HCD_ED ED;
1893 POHCI_HCD_ED PreviousED;
1894 POHCI_STATIC_ED HeadED;
1895
1896 DPRINT_OHCI("OHCI_RemoveEndpointFromSchedule \n");
1897
1898 ED = OhciEndpoint->HcdED;
1899 HeadED = OhciEndpoint->HeadED;
1900
1901 if (&HeadED->Link == ED->HcdEDLink.Blink)
1902 {
1903 if (HeadED->Type == OHCI_STATIC_ED_TYPE_CONTROL ||
1904 HeadED->Type == OHCI_STATIC_ED_TYPE_BULK)
1905 {
1906 WRITE_REGISTER_ULONG(HeadED->pNextED, ED->HwED.NextED);
1907 }
1908 else if (HeadED->Type == OHCI_STATIC_ED_TYPE_INTERRUPT)
1909 {
1910 *HeadED->pNextED = ED->HwED.NextED;
1911 }
1912 else
1913 {
1914 DPRINT1("OHCI_RemoveEndpointFromSchedule: Unknown HeadED->Type - %x\n",
1915 HeadED->Type);
1916 DbgBreakPoint();
1917 }
1918 }
1919 else
1920 {
1921 PreviousED = CONTAINING_RECORD(ED->HcdEDLink.Blink,
1922 OHCI_HCD_ED,
1923 HcdEDLink);
1924
1925 PreviousED->HwED.NextED = ED->HwED.NextED;
1926 }
1927
1928 RemoveEntryList(&ED->HcdEDLink);
1929
1930 OhciEndpoint->HeadED = NULL;
1931 }
1932
1933 VOID
1934 NTAPI
1935 OHCI_SetEndpointState(IN PVOID ohciExtension,
1936 IN PVOID ohciEndpoint,
1937 IN ULONG EndpointState)
1938 {
1939 POHCI_EXTENSION OhciExtension = ohciExtension;
1940 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1941 POHCI_HCD_ED ED;
1942
1943 DPRINT_OHCI("OHCI_SetEndpointState: EndpointState - %x\n",
1944 EndpointState);
1945
1946 ED = OhciEndpoint->HcdED;
1947
1948 switch (EndpointState)
1949 {
1950 case USBPORT_ENDPOINT_PAUSED:
1951 ED->HwED.EndpointControl.sKip = 1;
1952 break;
1953
1954 case USBPORT_ENDPOINT_ACTIVE:
1955 ED->HwED.EndpointControl.sKip = 0;
1956 OHCI_EnableList(OhciExtension, OhciEndpoint);
1957 break;
1958
1959 case USBPORT_ENDPOINT_REMOVE:
1960 ED->HwED.EndpointControl.sKip = 1;
1961 ED->Flags |= OHCI_HCD_ED_FLAG_NOT_ACCESSED;
1962 OHCI_RemoveEndpointFromSchedule(OhciEndpoint);
1963 break;
1964
1965 default:
1966 ASSERT(FALSE);
1967 break;
1968 }
1969 }
1970
1971 VOID
1972 NTAPI
1973 OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension,
1974 IN POHCI_ENDPOINT OhciEndpoint)
1975 {
1976 PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1977 POHCI_HCD_ED ED;
1978 ULONG_PTR NextTdPA;
1979 POHCI_HCD_TD NextTD;
1980 POHCI_HCD_TD TD;
1981 PLIST_ENTRY DoneList;
1982 POHCI_TRANSFER OhciTransfer;
1983 POHCI_HCD_TD ControlStatusTD;
1984 ULONG_PTR PhysicalAddress;
1985 ULONG TransferNumber;
1986 POHCI_TRANSFER transfer;
1987 UCHAR ConditionCode;
1988 BOOLEAN IsResetOnHalt = FALSE;
1989
1990 //DPRINT_OHCI("OHCI_PollAsyncEndpoint: Endpoint - %p\n", OhciEndpoint);
1991
1992 ED = OhciEndpoint->HcdED;
1993 NextTdPA = ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK;
1994
1995 if (!NextTdPA)
1996 {
1997 OHCI_DumpHcdED(ED);
1998 DbgBreakPoint();
1999 }
2000
2001 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA,
2002 OhciExtension,
2003 OhciEndpoint);
2004 DPRINT_OHCI("NextTD - %p\n", NextTD);
2005
2006 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) == 0)
2007 goto ProcessListTDs;
2008
2009 OHCI_DumpHcdED(ED);
2010
2011 IsResetOnHalt = (ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT) != 0;
2012 DPRINT1("PollAsyncEndpoint: IsResetOnHalt %x\n", IsResetOnHalt);
2013
2014 for (TD = OhciEndpoint->HcdHeadP; ; TD = TD->NextHcdTD)
2015 {
2016 if (!TD)
2017 {
2018 OHCI_DumpHcdED(ED);
2019 DbgBreakPoint();
2020 }
2021
2022 if (TD == NextTD)
2023 {
2024 DPRINT("TD == NextTD - %p\n", TD);
2025 goto HandleDoneList;
2026 }
2027
2028 OhciTransfer = TD->OhciTransfer;
2029 ConditionCode = TD->HwTD.gTD.Control.ConditionCode;
2030
2031 DPRINT("TD - %p, ConditionCode - %X\n", TD, ConditionCode);
2032 OHCI_DumpHcdTD(TD);
2033
2034 switch (ConditionCode)
2035 {
2036 case OHCI_TD_CONDITION_NO_ERROR:
2037 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2038 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2039 continue;
2040
2041 case OHCI_TD_CONDITION_NOT_ACCESSED:
2042 TD->Flags |= (OHCI_HCD_TD_FLAG_DONE | OHCI_HCD_TD_FLAG_NOT_ACCESSED);
2043 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2044 continue;
2045
2046 case OHCI_TD_CONDITION_DATA_UNDERRUN:
2047 DPRINT1("DATA_UNDERRUN. Transfer->Flags - %X\n", OhciTransfer->Flags);
2048
2049 if (OhciTransfer->Flags & OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK)
2050 {
2051 IsResetOnHalt = TRUE;
2052 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
2053
2054 ControlStatusTD = OhciTransfer->ControlStatusTD;
2055
2056 if ((TD->Flags & OHCI_HCD_TD_FLAG_CONTROL_STATUS) == 0 &&
2057 ControlStatusTD)
2058 {
2059 PhysicalAddress = ControlStatusTD->PhysicalAddress;
2060 PhysicalAddress |= (ED->HwED.HeadPointer &
2061 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2062
2063 ED->HwED.HeadPointer = PhysicalAddress;
2064
2065 NextTD = OhciTransfer->ControlStatusTD;
2066 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2067 }
2068 else
2069 {
2070 TransferParameters = OhciTransfer->TransferParameters;
2071
2072 if (TransferParameters->IsTransferSplited)
2073 {
2074 TransferNumber = TransferParameters->TransferCounter;
2075 transfer = OhciTransfer;
2076
2077 do
2078 {
2079 transfer = transfer->NextTD->OhciTransfer;
2080 NextTD = transfer->NextTD;
2081 }
2082 while (transfer && TransferNumber ==
2083 transfer->TransferParameters->TransferCounter);
2084
2085 PhysicalAddress = NextTD->PhysicalAddress;
2086 PhysicalAddress |= (ED->HwED.HeadPointer &
2087 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2088
2089 ED->HwED.HeadPointer = PhysicalAddress;
2090 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2091 }
2092 else
2093 {
2094 PhysicalAddress = OhciTransfer->NextTD->PhysicalAddress;
2095 PhysicalAddress |= (ED->HwED.HeadPointer &
2096 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2097
2098 ED->HwED.HeadPointer = PhysicalAddress;
2099
2100 NextTD = OhciTransfer->NextTD;
2101 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2102 }
2103 }
2104
2105 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2106 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2107 continue;
2108 }
2109
2110 /* fall through */
2111
2112 default:
2113 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2114 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2115
2116 ED->HwED.HeadPointer = OhciTransfer->NextTD->PhysicalAddress |
2117 (ED->HwED.HeadPointer &
2118 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2119
2120 NextTD = OhciTransfer->NextTD;
2121 break;
2122 }
2123 }
2124
2125 ProcessListTDs:
2126
2127 TD = OhciEndpoint->HcdHeadP;
2128
2129 while (TD != NextTD)
2130 {
2131 OHCI_DumpHcdTD(TD);
2132 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2133 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2134 TD = TD->NextHcdTD;
2135 }
2136
2137 HandleDoneList:
2138
2139 TD = NextTD;
2140 OhciEndpoint->HcdHeadP = NextTD;
2141
2142 DoneList = &OhciEndpoint->TDList;
2143
2144 while (!IsListEmpty(DoneList))
2145 {
2146 TD = CONTAINING_RECORD(DoneList->Flink,
2147 OHCI_HCD_TD,
2148 DoneLink);
2149
2150 RemoveHeadList(DoneList);
2151
2152 if (TD->Flags & OHCI_HCD_TD_FLAG_DONE &&
2153 TD->Flags & OHCI_HCD_TD_FLAG_PROCESSED)
2154 {
2155 OHCI_ProcessDoneTD(OhciExtension, TD, TRUE);
2156 }
2157 }
2158
2159 if (IsResetOnHalt)
2160 {
2161 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2162 DPRINT("ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer);
2163 }
2164 }
2165
2166 VOID
2167 NTAPI
2168 OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension,
2169 IN POHCI_ENDPOINT OhciEndpoint)
2170 {
2171 DPRINT1("OHCI_PollAsyncEndpoint: UNIMPLEMENTED. FIXME \n");
2172 ASSERT(FALSE);
2173 }
2174
2175 VOID
2176 NTAPI
2177 OHCI_PollEndpoint(IN PVOID ohciExtension,
2178 IN PVOID ohciEndpoint)
2179 {
2180 POHCI_EXTENSION OhciExtension = ohciExtension;
2181 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2182 ULONG TransferType;
2183
2184 DPRINT_OHCI("OHCI_PollEndpoint: OhciExtension - %p, Endpoint - %p\n",
2185 OhciExtension,
2186 OhciEndpoint);
2187
2188 TransferType = OhciEndpoint->EndpointProperties.TransferType;
2189
2190 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2191 {
2192 OHCI_PollIsoEndpoint(OhciExtension, OhciEndpoint);
2193 return;
2194 }
2195
2196 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2197 TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2198 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2199 {
2200 OHCI_PollAsyncEndpoint(OhciExtension, OhciEndpoint);
2201 }
2202 }
2203
2204 VOID
2205 NTAPI
2206 OHCI_CheckController(IN PVOID ohciExtension)
2207 {
2208 POHCI_EXTENSION OhciExtension = ohciExtension;
2209 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2210 PULONG HcControlReg;
2211 OHCI_REG_CONTROL HcControl;
2212 ULONG FmNumber;
2213 USHORT FmDiff;
2214 POHCI_HCCA HcHCCA;
2215
2216 //DPRINT_OHCI("OHCI_CheckController: ...\n");
2217
2218 OperationalRegs = OhciExtension->OperationalRegs;
2219
2220 if (!OHCI_HardwarePresent(OhciExtension, TRUE))
2221 return;
2222
2223 HcControlReg = (PULONG)&OperationalRegs->HcControl;
2224 HcControl.AsULONG = READ_REGISTER_ULONG(HcControlReg);
2225
2226 if (HcControl.HostControllerFunctionalState != OHCI_HC_STATE_OPERATIONAL)
2227 return;
2228
2229 FmNumber = READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber);
2230 FmDiff = (USHORT)(FmNumber - OhciExtension->HcdFmNumber);
2231
2232 if (FmNumber == 0 || FmDiff < 5)
2233 return;
2234
2235 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2236 OhciExtension->HcdFmNumber = FmNumber;
2237
2238 if (HcHCCA->Pad1 == 0)
2239 {
2240 HcHCCA->Pad1 = 0xBAD1;
2241 return;
2242 }
2243
2244 DPRINT1("OHCI_CheckController: HcHCCA->Pad1 - %x\n", HcHCCA->Pad1);
2245
2246 if (HcHCCA->Pad1 == 0xBAD1)
2247 {
2248 HcHCCA->Pad1 = 0xBAD2;
2249 }
2250 else if (HcHCCA->Pad1 == 0xBAD2)
2251 {
2252 HcHCCA->Pad1 = 0xBAD3;
2253
2254 RegPacket.UsbPortInvalidateController(OhciExtension,
2255 USBPORT_INVALIDATE_CONTROLLER_RESET);
2256 }
2257 }
2258
2259 ULONG
2260 NTAPI
2261 OHCI_Get32BitFrameNumber(IN PVOID ohciExtension)
2262 {
2263 POHCI_EXTENSION OhciExtension = ohciExtension;
2264 POHCI_HCCA HcHCCA;
2265 ULONG fm;
2266 ULONG hp;
2267
2268 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2269
2270 /* 5.4 FrameInterval Counter: Get32BitFrameNumber() */
2271
2272 hp = OhciExtension->FrameHighPart;
2273 fm = HcHCCA->FrameNumber;
2274
2275 DPRINT_OHCI("OHCI_Get32BitFrameNumber: hp - %lX, fm - %lX\n", hp, fm);
2276
2277 return ((fm & 0x7FFF) | hp) + ((fm ^ hp) & 0x8000);
2278 }
2279
2280 VOID
2281 NTAPI
2282 OHCI_InterruptNextSOF(IN PVOID ohciExtension)
2283 {
2284 POHCI_EXTENSION OhciExtension = ohciExtension;
2285 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2286 PULONG InterruptEnableReg;
2287 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2288
2289 DPRINT_OHCI("OHCI_InterruptNextSOF: OhciExtension - %p\n",
2290 OhciExtension);
2291
2292 OperationalRegs = OhciExtension->OperationalRegs;
2293 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2294
2295 /* Enable interrupt generation due to Start of Frame */
2296 IntEnable.AsULONG = 0;
2297 IntEnable.StartofFrame = 1;
2298
2299 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2300 }
2301
2302 VOID
2303 NTAPI
2304 OHCI_EnableInterrupts(IN PVOID ohciExtension)
2305 {
2306 POHCI_EXTENSION OhciExtension = ohciExtension;
2307 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2308 PULONG InterruptEnableReg;
2309 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2310
2311 DPRINT_OHCI("OHCI_EnableInterrupts: OhciExtension - %p\n",
2312 OhciExtension);
2313
2314 OperationalRegs = OhciExtension->OperationalRegs;
2315 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2316
2317 /* Enable interrupt generation */
2318 IntEnable.AsULONG = 0;
2319 IntEnable.MasterInterruptEnable = 1;
2320
2321 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2322 }
2323
2324 VOID
2325 NTAPI
2326 OHCI_DisableInterrupts(IN PVOID ohciExtension)
2327 {
2328 POHCI_EXTENSION OhciExtension = ohciExtension;
2329 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2330 PULONG InterruptDisableReg;
2331 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
2332
2333 DPRINT_OHCI("OHCI_DisableInterrupts\n");
2334
2335 OperationalRegs = OhciExtension->OperationalRegs;
2336 InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
2337
2338 /* Disable interrupt generation */
2339 IntDisable.AsULONG = 0;
2340 IntDisable.MasterInterruptEnable = 1;
2341
2342 WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
2343 }
2344
2345 VOID
2346 NTAPI
2347 OHCI_PollController(IN PVOID ohciExtension)
2348 {
2349 DPRINT1("OHCI_PollController: UNIMPLEMENTED. FIXME\n");
2350 }
2351
2352 VOID
2353 NTAPI
2354 OHCI_SetEndpointDataToggle(IN PVOID ohciExtension,
2355 IN PVOID ohciEndpoint,
2356 IN ULONG DataToggle)
2357 {
2358 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2359 POHCI_HCD_ED ED;
2360
2361 DPRINT_OHCI("OHCI_SetEndpointDataToggle: Endpoint - %p, DataToggle - %x\n",
2362 OhciEndpoint,
2363 DataToggle);
2364
2365 ED = OhciEndpoint->HcdED;
2366
2367 if (DataToggle)
2368 ED->HwED.HeadPointer |= OHCI_ED_HEAD_POINTER_CARRY;
2369 else
2370 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_CARRY;
2371 }
2372
2373 ULONG
2374 NTAPI
2375 OHCI_GetEndpointStatus(IN PVOID ohciExtension,
2376 IN PVOID ohciEndpoint)
2377 {
2378 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2379 POHCI_HCD_ED ED;
2380 ULONG EndpointStatus = USBPORT_ENDPOINT_RUN;
2381
2382 DPRINT_OHCI("OHCI_GetEndpointStatus: ... \n");
2383
2384 ED = OhciEndpoint->HcdED;
2385
2386 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) &&
2387 !(ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT))
2388 {
2389 EndpointStatus = USBPORT_ENDPOINT_HALT;
2390 }
2391
2392 return EndpointStatus;
2393 }
2394
2395 VOID
2396 NTAPI
2397 OHCI_SetEndpointStatus(IN PVOID ohciExtension,
2398 IN PVOID ohciEndpoint,
2399 IN ULONG EndpointStatus)
2400 {
2401 POHCI_EXTENSION OhciExtension = ohciExtension;
2402 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2403 POHCI_HCD_ED ED;
2404
2405 DPRINT_OHCI("OHCI_SetEndpointStatus: Endpoint - %p, EndpointStatus - %lX\n",
2406 OhciEndpoint,
2407 EndpointStatus);
2408
2409 if (EndpointStatus == USBPORT_ENDPOINT_RUN)
2410 {
2411 ED = OhciEndpoint->HcdED;
2412 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2413
2414 OHCI_EnableList(OhciExtension, OhciEndpoint);
2415 }
2416 else if (EndpointStatus == USBPORT_ENDPOINT_HALT)
2417 {
2418 ASSERT(FALSE);
2419 }
2420 }
2421
2422 VOID
2423 NTAPI
2424 OHCI_ResetController(IN PVOID ohciExtension)
2425 {
2426 POHCI_EXTENSION OhciExtension = ohciExtension;
2427 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2428 ULONG FrameNumber;
2429 PULONG ControlReg;
2430 PULONG CommandStatusReg;
2431 PULONG InterruptEnableReg;
2432 PULONG FmIntervalReg;
2433 PULONG RhStatusReg;
2434 PULONG PortStatusReg;
2435 OHCI_REG_CONTROL ControlBak;
2436 OHCI_REG_CONTROL Control;
2437 OHCI_REG_COMMAND_STATUS CommandStatus;
2438 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2439 ULONG_PTR HCCA;
2440 ULONG_PTR ControlHeadED;
2441 ULONG_PTR BulkHeadED;
2442 OHCI_REG_FRAME_INTERVAL FrameInterval;
2443 ULONG_PTR PeriodicStart;
2444 ULONG_PTR LSThreshold;
2445 OHCI_REG_RH_STATUS RhStatus;
2446 OHCI_REG_RH_DESCRIPTORA RhDescriptorA;
2447 OHCI_REG_RH_PORT_STATUS PortStatus;
2448 ULONG NumPorts;
2449 ULONG ix;
2450
2451 DPRINT("OHCI_ResetController: ... \n");
2452
2453 OperationalRegs = OhciExtension->OperationalRegs;
2454
2455 ControlReg = (PULONG)&OperationalRegs->HcControl;
2456 CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
2457 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2458 FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
2459 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
2460
2461 /* Backup FrameNumber from HcHCCA */
2462 FrameNumber = OhciExtension->HcResourcesVA->HcHCCA.FrameNumber;
2463
2464 /* Backup registers */
2465 ControlBak.AsULONG = READ_REGISTER_ULONG(ControlReg);
2466 HCCA = READ_REGISTER_ULONG(&OperationalRegs->HcHCCA);
2467 ControlHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcControlHeadED);
2468 BulkHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED);
2469 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
2470 PeriodicStart = READ_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart);
2471 LSThreshold = READ_REGISTER_ULONG(&OperationalRegs->HcLSThreshold);
2472
2473 /* Reset HostController */
2474 CommandStatus.AsULONG = 0;
2475 CommandStatus.HostControllerReset = 1;
2476 WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
2477
2478 KeStallExecutionProcessor(10);
2479
2480 /* Restore registers */
2481 WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA, HCCA);
2482 WRITE_REGISTER_ULONG(&OperationalRegs->HcControlHeadED, ControlHeadED);
2483 WRITE_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED, BulkHeadED);
2484
2485 /* Set OPERATIONAL state for HC */
2486 Control.AsULONG = 0;
2487 Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2488 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
2489
2490 /* Set Toggle bit for FmInterval register */
2491 FrameInterval.FrameIntervalToggle = 1;
2492 WRITE_REGISTER_ULONG(FmIntervalReg, FrameInterval.AsULONG);
2493
2494 /* Restore registers */
2495 WRITE_REGISTER_ULONG(&OperationalRegs->HcFmNumber, FrameNumber);
2496 WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart, PeriodicStart);
2497 WRITE_REGISTER_ULONG(&OperationalRegs->HcLSThreshold, LSThreshold);
2498
2499 /* Setup RhStatus register */
2500 RhStatus.AsULONG = 0;
2501 RhStatus.SetRemoteWakeupEnable = 1;
2502 RhStatus.SetGlobalPower = 1;
2503 WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
2504
2505 /* Setup RH PortStatus registers */
2506 RhDescriptorA = OHCI_ReadRhDescriptorA(OhciExtension);
2507 NumPorts = RhDescriptorA.NumberDownstreamPorts;
2508
2509 PortStatus.AsULONG = 0;
2510 PortStatus.SetPortPower = 1;
2511
2512 for (ix = 0; ix < NumPorts; ix++)
2513 {
2514 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[ix];
2515 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG);
2516 }
2517
2518 /* Restore HcControl register */
2519 ControlBak.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2520 WRITE_REGISTER_ULONG(ControlReg, ControlBak.AsULONG);
2521
2522 /* Setup HcInterruptEnable register */
2523 IntEnable.AsULONG = 0xFFFFFFFF;
2524 IntEnable.Reserved1 = 0;
2525 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2526 }
2527
2528 MPSTATUS
2529 NTAPI
2530 OHCI_StartSendOnePacket(IN PVOID ohciExtension,
2531 IN PVOID PacketParameters,
2532 IN PVOID Data,
2533 IN PULONG pDataLength,
2534 IN PVOID BufferVA,
2535 IN PVOID BufferPA,
2536 IN ULONG BufferLength,
2537 IN USBD_STATUS * pUSBDStatus)
2538 {
2539 DPRINT1("OHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n");
2540 return MP_STATUS_SUCCESS;
2541 }
2542
2543 MPSTATUS
2544 NTAPI
2545 OHCI_EndSendOnePacket(IN PVOID ohciExtension,
2546 IN PVOID PacketParameters,
2547 IN PVOID Data,
2548 IN PULONG pDataLength,
2549 IN PVOID BufferVA,
2550 IN PVOID BufferPA,
2551 IN ULONG BufferLength,
2552 IN USBD_STATUS * pUSBDStatus)
2553 {
2554 DPRINT1("OHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n");
2555 return MP_STATUS_SUCCESS;
2556 }
2557
2558 MPSTATUS
2559 NTAPI
2560 OHCI_PassThru(IN PVOID ohciExtension,
2561 IN PVOID passThruParameters,
2562 IN ULONG ParameterLength,
2563 IN PVOID pParameters)
2564 {
2565 DPRINT1("OHCI_PassThru: UNIMPLEMENTED. FIXME\n");
2566 return MP_STATUS_SUCCESS;
2567 }
2568
2569 VOID
2570 NTAPI
2571 OHCI_Unload(IN PDRIVER_OBJECT DriverObject)
2572 {
2573 #if DBG
2574 DPRINT1("OHCI_Unload: Not supported\n");
2575 #endif
2576 return;
2577 }
2578
2579 VOID
2580 NTAPI
2581 OHCI_FlushInterrupts(IN PVOID uhciExtension)
2582 {
2583 #if DBG
2584 DPRINT1("OHCI_FlushInterrupts: Not supported\n");
2585 #endif
2586 return;
2587 }
2588
2589 NTSTATUS
2590 NTAPI
2591 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2592 IN PUNICODE_STRING RegistryPath)
2593 {
2594 NTSTATUS Status;
2595
2596 DPRINT_OHCI("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n",
2597 DriverObject,
2598 RegistryPath);
2599
2600 RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET));
2601
2602 RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_OHCI;
2603
2604 RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT |
2605 USB_MINIPORT_FLAGS_MEMORY_IO;
2606
2607 RegPacket.MiniPortBusBandwidth = TOTAL_USB11_BUS_BANDWIDTH;
2608
2609 RegPacket.MiniPortExtensionSize = sizeof(OHCI_EXTENSION);
2610 RegPacket.MiniPortEndpointSize = sizeof(OHCI_ENDPOINT);
2611 RegPacket.MiniPortTransferSize = sizeof(OHCI_TRANSFER);
2612 RegPacket.MiniPortResourcesSize = sizeof(OHCI_HC_RESOURCES);
2613
2614 RegPacket.OpenEndpoint = OHCI_OpenEndpoint;
2615 RegPacket.ReopenEndpoint = OHCI_ReopenEndpoint;
2616 RegPacket.QueryEndpointRequirements = OHCI_QueryEndpointRequirements;
2617 RegPacket.CloseEndpoint = OHCI_CloseEndpoint;
2618 RegPacket.StartController = OHCI_StartController;
2619 RegPacket.StopController = OHCI_StopController;
2620 RegPacket.SuspendController = OHCI_SuspendController;
2621 RegPacket.ResumeController = OHCI_ResumeController;
2622 RegPacket.InterruptService = OHCI_InterruptService;
2623 RegPacket.InterruptDpc = OHCI_InterruptDpc;
2624 RegPacket.SubmitTransfer = OHCI_SubmitTransfer;
2625 RegPacket.SubmitIsoTransfer = OHCI_SubmitIsoTransfer;
2626 RegPacket.AbortTransfer = OHCI_AbortTransfer;
2627 RegPacket.GetEndpointState = OHCI_GetEndpointState;
2628 RegPacket.SetEndpointState = OHCI_SetEndpointState;
2629 RegPacket.PollEndpoint = OHCI_PollEndpoint;
2630 RegPacket.CheckController = OHCI_CheckController;
2631 RegPacket.Get32BitFrameNumber = OHCI_Get32BitFrameNumber;
2632 RegPacket.InterruptNextSOF = OHCI_InterruptNextSOF;
2633 RegPacket.EnableInterrupts = OHCI_EnableInterrupts;
2634 RegPacket.DisableInterrupts = OHCI_DisableInterrupts;
2635 RegPacket.PollController = OHCI_PollController;
2636 RegPacket.SetEndpointDataToggle = OHCI_SetEndpointDataToggle;
2637 RegPacket.GetEndpointStatus = OHCI_GetEndpointStatus;
2638 RegPacket.SetEndpointStatus = OHCI_SetEndpointStatus;
2639 RegPacket.ResetController = OHCI_ResetController;
2640 RegPacket.RH_GetRootHubData = OHCI_RH_GetRootHubData;
2641 RegPacket.RH_GetStatus = OHCI_RH_GetStatus;
2642 RegPacket.RH_GetPortStatus = OHCI_RH_GetPortStatus;
2643 RegPacket.RH_GetHubStatus = OHCI_RH_GetHubStatus;
2644 RegPacket.RH_SetFeaturePortReset = OHCI_RH_SetFeaturePortReset;
2645 RegPacket.RH_SetFeaturePortPower = OHCI_RH_SetFeaturePortPower;
2646 RegPacket.RH_SetFeaturePortEnable = OHCI_RH_SetFeaturePortEnable;
2647 RegPacket.RH_SetFeaturePortSuspend = OHCI_RH_SetFeaturePortSuspend;
2648 RegPacket.RH_ClearFeaturePortEnable = OHCI_RH_ClearFeaturePortEnable;
2649 RegPacket.RH_ClearFeaturePortPower = OHCI_RH_ClearFeaturePortPower;
2650 RegPacket.RH_ClearFeaturePortSuspend = OHCI_RH_ClearFeaturePortSuspend;
2651 RegPacket.RH_ClearFeaturePortEnableChange = OHCI_RH_ClearFeaturePortEnableChange;
2652 RegPacket.RH_ClearFeaturePortConnectChange = OHCI_RH_ClearFeaturePortConnectChange;
2653 RegPacket.RH_ClearFeaturePortResetChange = OHCI_RH_ClearFeaturePortResetChange;
2654 RegPacket.RH_ClearFeaturePortSuspendChange = OHCI_RH_ClearFeaturePortSuspendChange;
2655 RegPacket.RH_ClearFeaturePortOvercurrentChange = OHCI_RH_ClearFeaturePortOvercurrentChange;
2656 RegPacket.RH_DisableIrq = OHCI_RH_DisableIrq;
2657 RegPacket.RH_EnableIrq = OHCI_RH_EnableIrq;
2658 RegPacket.StartSendOnePacket = OHCI_StartSendOnePacket;
2659 RegPacket.EndSendOnePacket = OHCI_EndSendOnePacket;
2660 RegPacket.PassThru = OHCI_PassThru;
2661 RegPacket.FlushInterrupts = OHCI_FlushInterrupts;
2662
2663 DriverObject->DriverUnload = OHCI_Unload;
2664
2665 Status = USBPORT_RegisterUSBPortDriver(DriverObject,
2666 USB10_MINIPORT_INTERFACE_VERSION,
2667 &RegPacket);
2668
2669 DPRINT_OHCI("DriverEntry: USBPORT_RegisterUSBPortDriver return Status - %x\n",
2670 Status);
2671
2672 return Status;
2673 }