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
OHCI_DumpHcdED(POHCI_HCD_ED ED)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
OHCI_DumpHcdTD(POHCI_HCD_TD TD)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
OHCI_EnableList(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_InsertEndpointInSchedule(IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_InitializeED(IN POHCI_ENDPOINT OhciEndpoint,IN POHCI_HCD_ED ED,IN POHCI_HCD_TD FirstTD,IN ULONG_PTR EdPA)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
OHCI_InitializeTDs(IN POHCI_ENDPOINT OhciEndpoint,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties)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
OHCI_OpenControlEndpoint(IN POHCI_EXTENSION OhciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_OpenBulkEndpoint(IN POHCI_EXTENSION OhciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_OpenInterruptEndpoint(IN POHCI_EXTENSION OhciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_OpenIsoEndpoint(IN POHCI_EXTENSION OhciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_OpenEndpoint(IN PVOID ohciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN PVOID ohciEndpoint)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
OHCI_ReopenEndpoint(IN PVOID ohciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN PVOID ohciEndpoint)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
OHCI_QueryEndpointRequirements(IN PVOID ohciExtension,IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements)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
OHCI_CloseEndpoint(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN BOOLEAN IsDoDisablePeriodic)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
OHCI_TakeControlHC(IN POHCI_EXTENSION OhciExtension,IN PUSBPORT_RESOURCES Resources)529 OHCI_TakeControlHC(IN POHCI_EXTENSION OhciExtension,
530 IN PUSBPORT_RESOURCES Resources)
531 {
532 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
533 PULONG ControlReg;
534 PULONG InterruptEnableReg;
535 PULONG InterruptDisableReg;
536 PULONG CommandStatusReg;
537 PULONG InterruptStatusReg;
538 OHCI_REG_CONTROL Control;
539 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
540 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
541 OHCI_REG_COMMAND_STATUS CommandStatus;
542 OHCI_REG_INTERRUPT_STATUS IntStatus;
543 LARGE_INTEGER StartTicks, CurrentTicks;
544 UINT32 TicksDiff;
545
546 DPRINT("OHCI_TakeControlHC: ...\n");
547
548 OperationalRegs = OhciExtension->OperationalRegs;
549
550 ControlReg = (PULONG)&OperationalRegs->HcControl;
551 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
552 InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
553 CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
554 InterruptStatusReg = (PULONG)&OperationalRegs->HcInterruptStatus;
555
556 /* 5.1.1.3 Take Control of Host Controller */
557 Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
558
559 if (Control.InterruptRouting == 0)
560 return MP_STATUS_SUCCESS;
561
562 DPRINT1("OHCI_TakeControlHC: detected Legacy BIOS\n");
563
564 IntEnable.AsULONG = READ_REGISTER_ULONG(InterruptEnableReg);
565
566 DPRINT("OHCI_TakeControlHC: Control - %lX, IntEnable - %lX\n",
567 Control.AsULONG,
568 IntEnable.AsULONG);
569
570 if (Control.HostControllerFunctionalState == OHCI_HC_STATE_RESET &&
571 IntEnable.AsULONG == 0)
572 {
573 Control.AsULONG = 0;
574 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
575 return MP_STATUS_SUCCESS;
576 }
577
578 /* Enable interrupt generations */
579 IntEnable.AsULONG = 0;
580 IntEnable.MasterInterruptEnable = 1;
581
582 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
583
584 /* Request a change of control of the HC */
585 CommandStatus.AsULONG = 0;
586 CommandStatus.OwnershipChangeRequest = 1;
587
588 WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
589
590 /* Disable interrupt generation due to Root Hub Status Change */
591 IntDisable.AsULONG = 0;
592 IntDisable.RootHubStatusChange = 1;
593
594 WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
595
596 /* Monitoring the InterruptRouting bit
597 to determine when the ownership change has taken effect. */
598
599 TicksDiff = (500 * 10000) / KeQueryTimeIncrement(); // 500 ms
600 KeQueryTickCount(&StartTicks);
601
602 do
603 {
604 Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
605
606 if (Control.InterruptRouting == 0)
607 {
608 /* Clear all bits in register */
609 IntStatus.AsULONG = 0xFFFFFFFF;
610 WRITE_REGISTER_ULONG(InterruptStatusReg, IntStatus.AsULONG);
611
612 /* Disable interrupt generations */
613 IntDisable.AsULONG = 0;
614 IntDisable.MasterInterruptEnable = 1;
615
616 WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
617
618 return MP_STATUS_SUCCESS;
619 }
620
621 KeQueryTickCount(&CurrentTicks);
622 }
623 while (CurrentTicks.QuadPart - StartTicks.QuadPart < TicksDiff);
624
625 return MP_STATUS_HW_ERROR;
626 }
627
628 MPSTATUS
629 NTAPI
OHCI_StartController(IN PVOID ohciExtension,IN PUSBPORT_RESOURCES Resources)630 OHCI_StartController(IN PVOID ohciExtension,
631 IN PUSBPORT_RESOURCES Resources)
632 {
633 POHCI_EXTENSION OhciExtension = ohciExtension;
634 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
635 PULONG CommandStatusReg;
636 PULONG FmIntervalReg;
637 PULONG ControlReg;
638 PULONG InterruptEnableReg;
639 PULONG RhStatusReg;
640 OHCI_REG_COMMAND_STATUS CommandStatus;
641 OHCI_REG_INTERRUPT_ENABLE_DISABLE Interrupts;
642 OHCI_REG_RH_STATUS RhStatus;
643 OHCI_REG_FRAME_INTERVAL FrameInterval;
644 ULONG MaxFrameIntervalAdjusting;
645 OHCI_REG_CONTROL Control;
646 UCHAR HeadIndex;
647 POHCI_ENDPOINT_DESCRIPTOR IntED;
648 ULONG_PTR IntEdPA;
649 POHCI_HCCA OhciHCCA;
650 LARGE_INTEGER StartTicks, CurrentTicks;
651 UINT32 TicksDiff;
652 ULONG ix;
653 ULONG jx;
654 MPSTATUS MPStatus = MP_STATUS_SUCCESS;
655
656 DPRINT_OHCI("OHCI_StartController: ohciExtension - %p, Resources - %p\n",
657 ohciExtension,
658 Resources);
659
660 /* HC on-chip operational registers */
661 OperationalRegs = (POHCI_OPERATIONAL_REGISTERS)Resources->ResourceBase;
662 OhciExtension->OperationalRegs = OperationalRegs;
663
664 CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
665 FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
666 ControlReg = (PULONG)&OperationalRegs->HcControl;
667 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
668 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
669
670 /* 5.1.1 Initialization */
671
672 MPStatus = OHCI_TakeControlHC(OhciExtension, Resources);
673
674 if (MPStatus != MP_STATUS_SUCCESS)
675 {
676 DPRINT1("OHCI_StartController: OHCI_TakeControlHC return MPStatus - %x\n",
677 MPStatus);
678
679 return MPStatus;
680 }
681
682 OhciExtension->HcResourcesVA = (POHCI_HC_RESOURCES)Resources->StartVA;
683 OhciExtension->HcResourcesPA = Resources->StartPA;
684
685 DPRINT_OHCI("OHCI_StartController: HcResourcesVA - %p, HcResourcesPA - %lx\n",
686 OhciExtension->HcResourcesVA,
687 OhciExtension->HcResourcesPA);
688
689 /* 5.2.7.2 Interrupt */
690
691 /* Build structure of interrupt static EDs */
692 for (ix = 0; ix < INTERRUPT_ENDPOINTs; ix++)
693 {
694 IntED = &OhciExtension->HcResourcesVA->InterrruptHeadED[ix];
695 IntEdPA = OhciExtension->HcResourcesPA + FIELD_OFFSET(OHCI_HC_RESOURCES, InterrruptHeadED[ix]);
696
697 if (ix == (ENDPOINT_INTERRUPT_1ms - 1))
698 {
699 HeadIndex = ED_EOF;
700 IntED->NextED = 0;
701 }
702 else
703 {
704 HeadIndex = ((ix - 1) / 2);
705
706 ASSERT(HeadIndex >= (ENDPOINT_INTERRUPT_1ms - 1) &&
707 HeadIndex < (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms));
708
709 IntED->NextED = OhciExtension->IntStaticED[HeadIndex].PhysicalAddress;
710 }
711
712 IntED->EndpointControl.sKip = 1;
713
714 IntED->TailPointer = 0;
715 IntED->HeadPointer = 0;
716
717 OhciExtension->IntStaticED[ix].HwED = IntED;
718 OhciExtension->IntStaticED[ix].PhysicalAddress = IntEdPA;
719 OhciExtension->IntStaticED[ix].HeadIndex = HeadIndex;
720 OhciExtension->IntStaticED[ix].pNextED = &IntED->NextED;
721 OhciExtension->IntStaticED[ix].Type = OHCI_STATIC_ED_TYPE_INTERRUPT;
722
723 InitializeListHead(&OhciExtension->IntStaticED[ix].Link);
724 }
725
726 OhciHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
727 DPRINT_OHCI("OHCI_InitializeSchedule: OhciHCCA - %p\n", OhciHCCA);
728
729 /* Set head pointers which start from HCCA */
730 for (ix = 0, jx = (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms);
731 ix < OHCI_NUMBER_OF_INTERRUPTS;
732 ix++, jx++)
733 {
734 OhciHCCA->InterrruptTable[Balance[ix]] =
735 OhciExtension->IntStaticED[jx].PhysicalAddress;
736
737 OhciExtension->IntStaticED[jx].pNextED =
738 (PULONG)&OhciHCCA->InterrruptTable[Balance[ix]];
739
740 OhciExtension->IntStaticED[jx].HccaIndex = Balance[ix];
741 }
742
743 DPRINT_OHCI("OHCI_InitializeSchedule: ix - %x\n", ix);
744
745 /* Init static Control and Bulk EDs head pointers which start from HCCA */
746 InitializeListHead(&OhciExtension->ControlStaticED.Link);
747
748 OhciExtension->ControlStaticED.HeadIndex = ED_EOF;
749 OhciExtension->ControlStaticED.Type = OHCI_STATIC_ED_TYPE_CONTROL;
750 OhciExtension->ControlStaticED.pNextED = &OperationalRegs->HcControlHeadED;
751
752 InitializeListHead(&OhciExtension->BulkStaticED.Link);
753
754 OhciExtension->BulkStaticED.HeadIndex = ED_EOF;
755 OhciExtension->BulkStaticED.Type = OHCI_STATIC_ED_TYPE_BULK;
756 OhciExtension->BulkStaticED.pNextED = &OperationalRegs->HcBulkHeadED;
757
758 /* 6.3.1 Frame Timing */
759 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
760
761 MaxFrameIntervalAdjusting = OHCI_DEFAULT_FRAME_INTERVAL / 10; // 10%
762
763 if ((FrameInterval.FrameInterval) < (OHCI_DEFAULT_FRAME_INTERVAL - MaxFrameIntervalAdjusting) ||
764 (FrameInterval.FrameInterval) > (OHCI_DEFAULT_FRAME_INTERVAL + MaxFrameIntervalAdjusting))
765 {
766 FrameInterval.FrameInterval = OHCI_DEFAULT_FRAME_INTERVAL;
767 }
768
769 /* 5.4 FrameInterval Counter */
770 FrameInterval.FrameIntervalToggle = 1;
771
772 /* OHCI_MAXIMUM_OVERHEAD is the maximum overhead per frame */
773 FrameInterval.FSLargestDataPacket =
774 ((FrameInterval.FrameInterval - OHCI_MAXIMUM_OVERHEAD) * 6) / 7;
775
776 OhciExtension->FrameInterval = FrameInterval;
777
778 DPRINT_OHCI("OHCI_StartController: FrameInterval - %lX\n",
779 FrameInterval.AsULONG);
780
781 /* Reset HostController */
782 CommandStatus.AsULONG = 0;
783 CommandStatus.HostControllerReset = 1;
784
785 WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
786
787 KeStallExecutionProcessor(25);
788
789 Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
790 Control.HostControllerFunctionalState = OHCI_HC_STATE_RESET;
791
792 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
793
794 TicksDiff = (500 * 10000) / KeQueryTimeIncrement(); // 500 ms
795 KeQueryTickCount(&StartTicks);
796
797 while (TRUE)
798 {
799 WRITE_REGISTER_ULONG(FmIntervalReg, OhciExtension->FrameInterval.AsULONG);
800 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
801
802 KeQueryTickCount(&CurrentTicks);
803
804 if (CurrentTicks.QuadPart - StartTicks.QuadPart >= TicksDiff)
805 {
806 MPStatus = MP_STATUS_HW_ERROR;
807 break;
808 }
809
810 if (FrameInterval.AsULONG == OhciExtension->FrameInterval.AsULONG)
811 {
812 MPStatus = MP_STATUS_SUCCESS;
813 break;
814 }
815 }
816
817 if (MPStatus != MP_STATUS_SUCCESS)
818 {
819 DPRINT_OHCI("OHCI_StartController: frame interval not set\n");
820 return MPStatus;
821 }
822
823 /* Setup HcPeriodicStart register */
824 WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart,
825 (OhciExtension->FrameInterval.FrameInterval * 9) / 10); //90%
826
827 /* Setup HcHCCA register */
828 WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA,
829 OhciExtension->HcResourcesPA + FIELD_OFFSET(OHCI_HC_RESOURCES, HcHCCA));
830
831 /* Setup HcInterruptEnable register */
832 Interrupts.AsULONG = 0;
833
834 Interrupts.SchedulingOverrun = 1;
835 Interrupts.WritebackDoneHead = 1;
836 Interrupts.UnrecoverableError = 1;
837 Interrupts.FrameNumberOverflow = 1;
838 Interrupts.OwnershipChange = 1;
839
840 WRITE_REGISTER_ULONG(InterruptEnableReg, Interrupts.AsULONG);
841
842 /* Setup HcControl register */
843 Control.AsULONG = READ_REGISTER_ULONG(ControlReg);
844
845 Control.ControlBulkServiceRatio = 0; // FIXME (1 : 1)
846 Control.PeriodicListEnable = 1;
847 Control.IsochronousEnable = 1;
848 Control.ControlListEnable = 1;
849 Control.BulkListEnable = 1;
850 Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
851
852 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
853
854 /* Setup HcRhStatus register */
855 RhStatus.AsULONG = 0;
856 RhStatus.SetGlobalPower = 1;
857
858 WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
859
860 return MP_STATUS_SUCCESS;
861 }
862
863 VOID
864 NTAPI
OHCI_StopController(IN PVOID ohciExtension,IN BOOLEAN IsDoDisableInterrupts)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
OHCI_SuspendController(IN PVOID ohciExtension)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
OHCI_ResumeController(IN PVOID ohciExtension)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
OHCI_HardwarePresent(IN POHCI_EXTENSION OhciExtension,IN BOOLEAN IsInvalidateController)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
OHCI_InterruptService(IN PVOID ohciExtension)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
OHCI_InterruptDpc(IN PVOID ohciExtension,IN BOOLEAN IsDoEnableInterrupts)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
OHCI_MapTransferToTD(IN POHCI_EXTENSION OhciExtension,IN ULONG TransferedLen,IN POHCI_TRANSFER OhciTransfer,OUT POHCI_HCD_TD TD,IN PUSBPORT_SCATTER_GATHER_LIST SGList)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
OHCI_AllocateTD(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_RemainTDs(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint)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
OHCI_ControlTransfer(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint,IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,IN POHCI_TRANSFER OhciTransfer,IN PUSBPORT_SCATTER_GATHER_LIST SGList)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
OHCI_BulkOrInterruptTransfer(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint,IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,IN POHCI_TRANSFER OhciTransfer,IN PUSBPORT_SCATTER_GATHER_LIST SGList)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
OHCI_SubmitTransfer(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,IN PVOID ohciTransfer,IN PUSBPORT_SCATTER_GATHER_LIST SGList)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
OHCI_SubmitIsoTransfer(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,IN PVOID ohciTransfer,IN PVOID isoParameters)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
OHCI_ProcessDoneTD(IN POHCI_EXTENSION OhciExtension,IN POHCI_HCD_TD TD,IN BOOLEAN IsPortComplete)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
OHCI_ProcessDoneIsoTD(IN POHCI_EXTENSION OhciExtension,IN POHCI_HCD_TD TD,IN BOOLEAN IsPortComplete)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
OHCI_AbortTransfer(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN PVOID ohciTransfer,IN OUT PULONG CompletedLength)1673 OHCI_AbortTransfer(IN PVOID ohciExtension,
1674 IN PVOID ohciEndpoint,
1675 IN PVOID ohciTransfer,
1676 IN OUT PULONG CompletedLength)
1677 {
1678 POHCI_EXTENSION OhciExtension = ohciExtension;
1679 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1680 POHCI_TRANSFER OhciTransfer = ohciTransfer;
1681 POHCI_HCD_ED ED = OhciEndpoint->HcdED;
1682 POHCI_HCD_TD TD, NextTD, LastTD;
1683 ULONG ix;
1684 BOOLEAN IsIsoEndpoint;
1685 BOOLEAN IsProcessed = FALSE;
1686
1687 DPRINT("OHCI_AbortTransfer: ohciEndpoint - %p, ohciTransfer - %p\n",
1688 OhciEndpoint,
1689 OhciTransfer);
1690
1691 IsIsoEndpoint = (OhciEndpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS);
1692 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK,
1693 OhciExtension,
1694 OhciEndpoint);
1695
1696 if (NextTD->OhciTransfer == OhciTransfer)
1697 {
1698 LastTD = OhciTransfer->NextTD;
1699
1700 /* Keeping the carry bit from previous pointer value */
1701 ED->HwED.HeadPointer = LastTD->PhysicalAddress |
1702 (ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_CARRY);
1703
1704 OhciEndpoint->HcdHeadP = LastTD;
1705
1706 for (ix = 0; ix < OhciEndpoint->MaxTransferDescriptors; ix++)
1707 {
1708 TD = &OhciEndpoint->FirstTD[ix];
1709
1710 if (TD->OhciTransfer != OhciTransfer)
1711 continue;
1712
1713 if (IsIsoEndpoint)
1714 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1715 else
1716 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1717 }
1718
1719 *CompletedLength = OhciTransfer->TransferLen;
1720 return;
1721 }
1722
1723 if (NextTD == OhciEndpoint->HcdHeadP)
1724 IsProcessed = TRUE;
1725
1726 for (TD = OhciEndpoint->HcdHeadP; TD != NextTD; TD = TD->NextTDVa)
1727 {
1728 if (TD->OhciTransfer != OhciTransfer)
1729 continue;
1730
1731 if (OhciEndpoint->HcdHeadP == TD)
1732 OhciEndpoint->HcdHeadP = TD->NextTDVa;
1733
1734 if (IsIsoEndpoint)
1735 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1736 else
1737 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1738
1739 IsProcessed = TRUE;
1740 }
1741
1742 if (!IsProcessed)
1743 {
1744 for (TD = OhciEndpoint->HcdHeadP; TD->OhciTransfer != OhciTransfer; TD = TD->NextTDVa)
1745 {
1746 if (TD == OhciEndpoint->HcdTailP)
1747 {
1748 TD = NULL;
1749 break;
1750 }
1751 LastTD = TD;
1752 }
1753
1754 for (; TD->OhciTransfer == OhciTransfer; TD = TD->NextTDVa)
1755 {
1756 if (TD == OhciEndpoint->HcdTailP)
1757 break;
1758
1759 if (IsIsoEndpoint)
1760 OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE);
1761 else
1762 OHCI_ProcessDoneTD(OhciExtension, TD, FALSE);
1763 }
1764
1765 LastTD->OhciTransfer->NextTD = TD;
1766
1767 LastTD->NextTDVa = TD;
1768 LastTD->HwTD.gTD.NextTD = TD->PhysicalAddress;
1769 }
1770
1771 *CompletedLength = OhciTransfer->TransferLen;
1772
1773 if (OhciTransfer->TransferLen)
1774 {
1775 DPRINT("OHCI_AbortTransfer: *CompletedLength - %x\n", *CompletedLength);
1776 }
1777 }
1778
1779 ULONG
1780 NTAPI
OHCI_GetEndpointState(IN PVOID ohciExtension,IN PVOID ohciEndpoint)1781 OHCI_GetEndpointState(IN PVOID ohciExtension,
1782 IN PVOID ohciEndpoint)
1783 {
1784 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1785 POHCI_HCD_ED ED;
1786
1787 DPRINT_OHCI("OHCI_GetEndpointState: ... \n");
1788
1789 ED = OhciEndpoint->HcdED;
1790
1791 if (ED->Flags & OHCI_HCD_TD_FLAG_NOT_ACCESSED)
1792 return USBPORT_ENDPOINT_REMOVE;
1793
1794 if (ED->HwED.EndpointControl.sKip)
1795 return USBPORT_ENDPOINT_PAUSED;
1796
1797 return USBPORT_ENDPOINT_ACTIVE;
1798 }
1799
1800 VOID
1801 NTAPI
OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint)1802 OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint)
1803 {
1804 POHCI_HCD_ED ED;
1805 POHCI_HCD_ED PreviousED;
1806 POHCI_STATIC_ED HeadED;
1807
1808 DPRINT_OHCI("OHCI_RemoveEndpointFromSchedule \n");
1809
1810 ED = OhciEndpoint->HcdED;
1811 HeadED = OhciEndpoint->HeadED;
1812
1813 if (&HeadED->Link == ED->HcdEDLink.Blink)
1814 {
1815 if (HeadED->Type == OHCI_STATIC_ED_TYPE_CONTROL ||
1816 HeadED->Type == OHCI_STATIC_ED_TYPE_BULK)
1817 {
1818 WRITE_REGISTER_ULONG(HeadED->pNextED, ED->HwED.NextED);
1819 }
1820 else if (HeadED->Type == OHCI_STATIC_ED_TYPE_INTERRUPT)
1821 {
1822 *HeadED->pNextED = ED->HwED.NextED;
1823 }
1824 else
1825 {
1826 DPRINT1("OHCI_RemoveEndpointFromSchedule: Unknown HeadED->Type - %x\n",
1827 HeadED->Type);
1828 DbgBreakPoint();
1829 }
1830 }
1831 else
1832 {
1833 PreviousED = CONTAINING_RECORD(ED->HcdEDLink.Blink,
1834 OHCI_HCD_ED,
1835 HcdEDLink);
1836
1837 PreviousED->HwED.NextED = ED->HwED.NextED;
1838 }
1839
1840 RemoveEntryList(&ED->HcdEDLink);
1841
1842 OhciEndpoint->HeadED = NULL;
1843 }
1844
1845 VOID
1846 NTAPI
OHCI_SetEndpointState(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN ULONG EndpointState)1847 OHCI_SetEndpointState(IN PVOID ohciExtension,
1848 IN PVOID ohciEndpoint,
1849 IN ULONG EndpointState)
1850 {
1851 POHCI_EXTENSION OhciExtension = ohciExtension;
1852 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
1853 POHCI_HCD_ED ED;
1854
1855 DPRINT_OHCI("OHCI_SetEndpointState: EndpointState - %x\n",
1856 EndpointState);
1857
1858 ED = OhciEndpoint->HcdED;
1859
1860 switch (EndpointState)
1861 {
1862 case USBPORT_ENDPOINT_PAUSED:
1863 ED->HwED.EndpointControl.sKip = 1;
1864 break;
1865
1866 case USBPORT_ENDPOINT_ACTIVE:
1867 ED->HwED.EndpointControl.sKip = 0;
1868 OHCI_EnableList(OhciExtension, OhciEndpoint);
1869 break;
1870
1871 case USBPORT_ENDPOINT_REMOVE:
1872 ED->HwED.EndpointControl.sKip = 1;
1873 ED->Flags |= OHCI_HCD_ED_FLAG_NOT_ACCESSED;
1874 OHCI_RemoveEndpointFromSchedule(OhciEndpoint);
1875 break;
1876
1877 default:
1878 ASSERT(FALSE);
1879 break;
1880 }
1881 }
1882
1883 VOID
1884 NTAPI
OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint)1885 OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension,
1886 IN POHCI_ENDPOINT OhciEndpoint)
1887 {
1888 PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1889 POHCI_HCD_ED ED;
1890 ULONG_PTR NextTdPA;
1891 POHCI_HCD_TD NextTD;
1892 POHCI_HCD_TD TD;
1893 PLIST_ENTRY DoneList;
1894 POHCI_TRANSFER OhciTransfer;
1895 POHCI_HCD_TD ControlStatusTD;
1896 ULONG_PTR PhysicalAddress;
1897 ULONG TransferNumber;
1898 POHCI_TRANSFER transfer;
1899 UCHAR ConditionCode;
1900 BOOLEAN IsResetOnHalt = FALSE;
1901
1902 //DPRINT_OHCI("OHCI_PollAsyncEndpoint: Endpoint - %p\n", OhciEndpoint);
1903
1904 ED = OhciEndpoint->HcdED;
1905 NextTdPA = ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_MASK;
1906
1907 if (!NextTdPA)
1908 {
1909 OHCI_DumpHcdED(ED);
1910 DbgBreakPoint();
1911 }
1912
1913 NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA,
1914 OhciExtension,
1915 OhciEndpoint);
1916 DPRINT_OHCI("NextTD - %p\n", NextTD);
1917
1918 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) == 0)
1919 goto ProcessListTDs;
1920
1921 OHCI_DumpHcdED(ED);
1922
1923 IsResetOnHalt = (ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT) != 0;
1924 DPRINT1("PollAsyncEndpoint: IsResetOnHalt %x\n", IsResetOnHalt);
1925
1926 for (TD = OhciEndpoint->HcdHeadP; ; TD = TD->NextTDVa)
1927 {
1928 if (!TD)
1929 {
1930 OHCI_DumpHcdED(ED);
1931 DbgBreakPoint();
1932 }
1933
1934 if (TD == NextTD)
1935 {
1936 DPRINT("TD == NextTD - %p\n", TD);
1937 goto HandleDoneList;
1938 }
1939
1940 OhciTransfer = TD->OhciTransfer;
1941 ConditionCode = TD->HwTD.gTD.Control.ConditionCode;
1942
1943 DPRINT("TD - %p, ConditionCode - %X\n", TD, ConditionCode);
1944 OHCI_DumpHcdTD(TD);
1945
1946 switch (ConditionCode)
1947 {
1948 case OHCI_TD_CONDITION_NO_ERROR:
1949 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
1950 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1951 continue;
1952
1953 case OHCI_TD_CONDITION_NOT_ACCESSED:
1954 TD->Flags |= (OHCI_HCD_TD_FLAG_DONE | OHCI_HCD_TD_FLAG_NOT_ACCESSED);
1955 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
1956 continue;
1957
1958 case OHCI_TD_CONDITION_DATA_UNDERRUN:
1959 DPRINT1("DATA_UNDERRUN. Transfer->Flags - %X\n", OhciTransfer->Flags);
1960
1961 if (OhciTransfer->Flags & OHCI_TRANSFER_FLAGS_SHORT_TRANSFER_OK)
1962 {
1963 IsResetOnHalt = TRUE;
1964 TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NO_ERROR;
1965
1966 ControlStatusTD = OhciTransfer->ControlStatusTD;
1967
1968 if ((TD->Flags & OHCI_HCD_TD_FLAG_CONTROL_STATUS) == 0 &&
1969 ControlStatusTD)
1970 {
1971 PhysicalAddress = ControlStatusTD->PhysicalAddress;
1972 PhysicalAddress |= (ED->HwED.HeadPointer &
1973 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
1974
1975 ED->HwED.HeadPointer = PhysicalAddress;
1976
1977 NextTD = OhciTransfer->ControlStatusTD;
1978 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
1979 }
1980 else
1981 {
1982 TransferParameters = OhciTransfer->TransferParameters;
1983
1984 if (TransferParameters->IsTransferSplited)
1985 {
1986 TransferNumber = TransferParameters->TransferCounter;
1987 transfer = OhciTransfer;
1988
1989 do
1990 {
1991 transfer = transfer->NextTD->OhciTransfer;
1992 NextTD = transfer->NextTD;
1993 }
1994 while (transfer && TransferNumber ==
1995 transfer->TransferParameters->TransferCounter);
1996
1997 PhysicalAddress = NextTD->PhysicalAddress;
1998 PhysicalAddress |= (ED->HwED.HeadPointer &
1999 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2000
2001 ED->HwED.HeadPointer = PhysicalAddress;
2002 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2003 }
2004 else
2005 {
2006 PhysicalAddress = OhciTransfer->NextTD->PhysicalAddress;
2007 PhysicalAddress |= (ED->HwED.HeadPointer &
2008 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2009
2010 ED->HwED.HeadPointer = PhysicalAddress;
2011
2012 NextTD = OhciTransfer->NextTD;
2013 DPRINT("PhysicalAddress - %p, NextTD - %p\n", PhysicalAddress, NextTD);
2014 }
2015 }
2016
2017 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2018 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2019 continue;
2020 }
2021
2022 /* fall through */
2023
2024 default:
2025 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2026 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2027
2028 ED->HwED.HeadPointer = OhciTransfer->NextTD->PhysicalAddress |
2029 (ED->HwED.HeadPointer &
2030 OHCI_ED_HEAD_POINTER_FLAGS_MASK);
2031
2032 NextTD = OhciTransfer->NextTD;
2033 break;
2034 }
2035 }
2036
2037 ProcessListTDs:
2038
2039 TD = OhciEndpoint->HcdHeadP;
2040
2041 while (TD != NextTD)
2042 {
2043 OHCI_DumpHcdTD(TD);
2044 TD->Flags |= OHCI_HCD_TD_FLAG_DONE;
2045 InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink);
2046 TD = TD->NextTDVa;
2047 }
2048
2049 HandleDoneList:
2050
2051 TD = NextTD;
2052 OhciEndpoint->HcdHeadP = NextTD;
2053
2054 DoneList = &OhciEndpoint->TDList;
2055
2056 while (!IsListEmpty(DoneList))
2057 {
2058 TD = CONTAINING_RECORD(DoneList->Flink,
2059 OHCI_HCD_TD,
2060 DoneLink);
2061
2062 RemoveHeadList(DoneList);
2063
2064 if (TD->Flags & OHCI_HCD_TD_FLAG_DONE &&
2065 TD->Flags & OHCI_HCD_TD_FLAG_PROCESSED)
2066 {
2067 OHCI_ProcessDoneTD(OhciExtension, TD, TRUE);
2068 }
2069 }
2070
2071 if (IsResetOnHalt)
2072 {
2073 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2074 DPRINT("ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer);
2075 }
2076 }
2077
2078 VOID
2079 NTAPI
OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension,IN POHCI_ENDPOINT OhciEndpoint)2080 OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension,
2081 IN POHCI_ENDPOINT OhciEndpoint)
2082 {
2083 DPRINT1("OHCI_PollAsyncEndpoint: UNIMPLEMENTED. FIXME \n");
2084 ASSERT(FALSE);
2085 }
2086
2087 VOID
2088 NTAPI
OHCI_PollEndpoint(IN PVOID ohciExtension,IN PVOID ohciEndpoint)2089 OHCI_PollEndpoint(IN PVOID ohciExtension,
2090 IN PVOID ohciEndpoint)
2091 {
2092 POHCI_EXTENSION OhciExtension = ohciExtension;
2093 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2094 ULONG TransferType;
2095
2096 DPRINT_OHCI("OHCI_PollEndpoint: OhciExtension - %p, Endpoint - %p\n",
2097 OhciExtension,
2098 OhciEndpoint);
2099
2100 TransferType = OhciEndpoint->EndpointProperties.TransferType;
2101
2102 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2103 {
2104 OHCI_PollIsoEndpoint(OhciExtension, OhciEndpoint);
2105 return;
2106 }
2107
2108 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2109 TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2110 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2111 {
2112 OHCI_PollAsyncEndpoint(OhciExtension, OhciEndpoint);
2113 }
2114 }
2115
2116 VOID
2117 NTAPI
OHCI_CheckController(IN PVOID ohciExtension)2118 OHCI_CheckController(IN PVOID ohciExtension)
2119 {
2120 POHCI_EXTENSION OhciExtension = ohciExtension;
2121 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2122 PULONG HcControlReg;
2123 OHCI_REG_CONTROL HcControl;
2124 ULONG FmNumber;
2125 USHORT FmDiff;
2126 POHCI_HCCA HcHCCA;
2127
2128 //DPRINT_OHCI("OHCI_CheckController: ...\n");
2129
2130 OperationalRegs = OhciExtension->OperationalRegs;
2131
2132 if (!OHCI_HardwarePresent(OhciExtension, TRUE))
2133 return;
2134
2135 HcControlReg = (PULONG)&OperationalRegs->HcControl;
2136 HcControl.AsULONG = READ_REGISTER_ULONG(HcControlReg);
2137
2138 if (HcControl.HostControllerFunctionalState != OHCI_HC_STATE_OPERATIONAL)
2139 return;
2140
2141 FmNumber = READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber);
2142 FmDiff = (USHORT)(FmNumber - OhciExtension->HcdFmNumber);
2143
2144 if (FmNumber == 0 || FmDiff < 5)
2145 return;
2146
2147 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2148 OhciExtension->HcdFmNumber = FmNumber;
2149
2150 if (HcHCCA->Pad1 == 0)
2151 {
2152 HcHCCA->Pad1 = 0xBAD1;
2153 return;
2154 }
2155
2156 DPRINT1("OHCI_CheckController: HcHCCA->Pad1 - %x\n", HcHCCA->Pad1);
2157
2158 if (HcHCCA->Pad1 == 0xBAD1)
2159 {
2160 HcHCCA->Pad1 = 0xBAD2;
2161 }
2162 else if (HcHCCA->Pad1 == 0xBAD2)
2163 {
2164 HcHCCA->Pad1 = 0xBAD3;
2165
2166 RegPacket.UsbPortInvalidateController(OhciExtension,
2167 USBPORT_INVALIDATE_CONTROLLER_RESET);
2168 }
2169 }
2170
2171 ULONG
2172 NTAPI
OHCI_Get32BitFrameNumber(IN PVOID ohciExtension)2173 OHCI_Get32BitFrameNumber(IN PVOID ohciExtension)
2174 {
2175 POHCI_EXTENSION OhciExtension = ohciExtension;
2176 POHCI_HCCA HcHCCA;
2177 ULONG fm;
2178 ULONG hp;
2179
2180 HcHCCA = &OhciExtension->HcResourcesVA->HcHCCA;
2181
2182 /* 5.4 FrameInterval Counter: Get32BitFrameNumber() */
2183
2184 hp = OhciExtension->FrameHighPart;
2185 fm = HcHCCA->FrameNumber;
2186
2187 DPRINT_OHCI("OHCI_Get32BitFrameNumber: hp - %lX, fm - %lX\n", hp, fm);
2188
2189 return ((fm & 0x7FFF) | hp) + ((fm ^ hp) & 0x8000);
2190 }
2191
2192 VOID
2193 NTAPI
OHCI_InterruptNextSOF(IN PVOID ohciExtension)2194 OHCI_InterruptNextSOF(IN PVOID ohciExtension)
2195 {
2196 POHCI_EXTENSION OhciExtension = ohciExtension;
2197 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2198 PULONG InterruptEnableReg;
2199 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2200
2201 DPRINT_OHCI("OHCI_InterruptNextSOF: OhciExtension - %p\n",
2202 OhciExtension);
2203
2204 OperationalRegs = OhciExtension->OperationalRegs;
2205 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2206
2207 /* Enable interrupt generation due to Start of Frame */
2208 IntEnable.AsULONG = 0;
2209 IntEnable.StartofFrame = 1;
2210
2211 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2212 }
2213
2214 VOID
2215 NTAPI
OHCI_EnableInterrupts(IN PVOID ohciExtension)2216 OHCI_EnableInterrupts(IN PVOID ohciExtension)
2217 {
2218 POHCI_EXTENSION OhciExtension = ohciExtension;
2219 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2220 PULONG InterruptEnableReg;
2221 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2222
2223 DPRINT_OHCI("OHCI_EnableInterrupts: OhciExtension - %p\n",
2224 OhciExtension);
2225
2226 OperationalRegs = OhciExtension->OperationalRegs;
2227 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2228
2229 /* Enable interrupt generation */
2230 IntEnable.AsULONG = 0;
2231 IntEnable.MasterInterruptEnable = 1;
2232
2233 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2234 }
2235
2236 VOID
2237 NTAPI
OHCI_DisableInterrupts(IN PVOID ohciExtension)2238 OHCI_DisableInterrupts(IN PVOID ohciExtension)
2239 {
2240 POHCI_EXTENSION OhciExtension = ohciExtension;
2241 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2242 PULONG InterruptDisableReg;
2243 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntDisable;
2244
2245 DPRINT_OHCI("OHCI_DisableInterrupts\n");
2246
2247 OperationalRegs = OhciExtension->OperationalRegs;
2248 InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable;
2249
2250 /* Disable interrupt generation */
2251 IntDisable.AsULONG = 0;
2252 IntDisable.MasterInterruptEnable = 1;
2253
2254 WRITE_REGISTER_ULONG(InterruptDisableReg, IntDisable.AsULONG);
2255 }
2256
2257 VOID
2258 NTAPI
OHCI_PollController(IN PVOID ohciExtension)2259 OHCI_PollController(IN PVOID ohciExtension)
2260 {
2261 DPRINT1("OHCI_PollController: UNIMPLEMENTED. FIXME\n");
2262 }
2263
2264 VOID
2265 NTAPI
OHCI_SetEndpointDataToggle(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN ULONG DataToggle)2266 OHCI_SetEndpointDataToggle(IN PVOID ohciExtension,
2267 IN PVOID ohciEndpoint,
2268 IN ULONG DataToggle)
2269 {
2270 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2271 POHCI_HCD_ED ED;
2272
2273 DPRINT_OHCI("OHCI_SetEndpointDataToggle: Endpoint - %p, DataToggle - %x\n",
2274 OhciEndpoint,
2275 DataToggle);
2276
2277 ED = OhciEndpoint->HcdED;
2278
2279 if (DataToggle)
2280 ED->HwED.HeadPointer |= OHCI_ED_HEAD_POINTER_CARRY;
2281 else
2282 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_CARRY;
2283 }
2284
2285 ULONG
2286 NTAPI
OHCI_GetEndpointStatus(IN PVOID ohciExtension,IN PVOID ohciEndpoint)2287 OHCI_GetEndpointStatus(IN PVOID ohciExtension,
2288 IN PVOID ohciEndpoint)
2289 {
2290 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2291 POHCI_HCD_ED ED;
2292 ULONG EndpointStatus = USBPORT_ENDPOINT_RUN;
2293
2294 DPRINT_OHCI("OHCI_GetEndpointStatus: ... \n");
2295
2296 ED = OhciEndpoint->HcdED;
2297
2298 if ((ED->HwED.HeadPointer & OHCI_ED_HEAD_POINTER_HALT) &&
2299 !(ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT))
2300 {
2301 EndpointStatus = USBPORT_ENDPOINT_HALT;
2302 }
2303
2304 return EndpointStatus;
2305 }
2306
2307 VOID
2308 NTAPI
OHCI_SetEndpointStatus(IN PVOID ohciExtension,IN PVOID ohciEndpoint,IN ULONG EndpointStatus)2309 OHCI_SetEndpointStatus(IN PVOID ohciExtension,
2310 IN PVOID ohciEndpoint,
2311 IN ULONG EndpointStatus)
2312 {
2313 POHCI_EXTENSION OhciExtension = ohciExtension;
2314 POHCI_ENDPOINT OhciEndpoint = ohciEndpoint;
2315 POHCI_HCD_ED ED;
2316
2317 DPRINT_OHCI("OHCI_SetEndpointStatus: Endpoint - %p, EndpointStatus - %lX\n",
2318 OhciEndpoint,
2319 EndpointStatus);
2320
2321 if (EndpointStatus == USBPORT_ENDPOINT_RUN)
2322 {
2323 ED = OhciEndpoint->HcdED;
2324 ED->HwED.HeadPointer &= ~OHCI_ED_HEAD_POINTER_HALT;
2325
2326 OHCI_EnableList(OhciExtension, OhciEndpoint);
2327 }
2328 else if (EndpointStatus == USBPORT_ENDPOINT_HALT)
2329 {
2330 ASSERT(FALSE);
2331 }
2332 }
2333
2334 VOID
2335 NTAPI
OHCI_ResetController(IN PVOID ohciExtension)2336 OHCI_ResetController(IN PVOID ohciExtension)
2337 {
2338 POHCI_EXTENSION OhciExtension = ohciExtension;
2339 POHCI_OPERATIONAL_REGISTERS OperationalRegs;
2340 ULONG FrameNumber;
2341 PULONG ControlReg;
2342 PULONG CommandStatusReg;
2343 PULONG InterruptEnableReg;
2344 PULONG FmIntervalReg;
2345 PULONG RhStatusReg;
2346 PULONG PortStatusReg;
2347 OHCI_REG_CONTROL ControlBak;
2348 OHCI_REG_CONTROL Control;
2349 OHCI_REG_COMMAND_STATUS CommandStatus;
2350 OHCI_REG_INTERRUPT_ENABLE_DISABLE IntEnable;
2351 ULONG_PTR HCCA;
2352 ULONG_PTR ControlHeadED;
2353 ULONG_PTR BulkHeadED;
2354 OHCI_REG_FRAME_INTERVAL FrameInterval;
2355 ULONG_PTR PeriodicStart;
2356 ULONG_PTR LSThreshold;
2357 OHCI_REG_RH_STATUS RhStatus;
2358 OHCI_REG_RH_DESCRIPTORA RhDescriptorA;
2359 OHCI_REG_RH_PORT_STATUS PortStatus;
2360 ULONG NumPorts;
2361 ULONG ix;
2362
2363 DPRINT("OHCI_ResetController: ... \n");
2364
2365 OperationalRegs = OhciExtension->OperationalRegs;
2366
2367 ControlReg = (PULONG)&OperationalRegs->HcControl;
2368 CommandStatusReg = (PULONG)&OperationalRegs->HcCommandStatus;
2369 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable;
2370 FmIntervalReg = (PULONG)&OperationalRegs->HcFmInterval;
2371 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus;
2372
2373 /* Backup FrameNumber from HcHCCA */
2374 FrameNumber = OhciExtension->HcResourcesVA->HcHCCA.FrameNumber;
2375
2376 /* Backup registers */
2377 ControlBak.AsULONG = READ_REGISTER_ULONG(ControlReg);
2378 HCCA = READ_REGISTER_ULONG(&OperationalRegs->HcHCCA);
2379 ControlHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcControlHeadED);
2380 BulkHeadED = READ_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED);
2381 FrameInterval.AsULONG = READ_REGISTER_ULONG(FmIntervalReg);
2382 PeriodicStart = READ_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart);
2383 LSThreshold = READ_REGISTER_ULONG(&OperationalRegs->HcLSThreshold);
2384
2385 /* Reset HostController */
2386 CommandStatus.AsULONG = 0;
2387 CommandStatus.HostControllerReset = 1;
2388 WRITE_REGISTER_ULONG(CommandStatusReg, CommandStatus.AsULONG);
2389
2390 KeStallExecutionProcessor(10);
2391
2392 /* Restore registers */
2393 WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA, HCCA);
2394 WRITE_REGISTER_ULONG(&OperationalRegs->HcControlHeadED, ControlHeadED);
2395 WRITE_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED, BulkHeadED);
2396
2397 /* Set OPERATIONAL state for HC */
2398 Control.AsULONG = 0;
2399 Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2400 WRITE_REGISTER_ULONG(ControlReg, Control.AsULONG);
2401
2402 /* Set Toggle bit for FmInterval register */
2403 FrameInterval.FrameIntervalToggle = 1;
2404 WRITE_REGISTER_ULONG(FmIntervalReg, FrameInterval.AsULONG);
2405
2406 /* Restore registers */
2407 WRITE_REGISTER_ULONG(&OperationalRegs->HcFmNumber, FrameNumber);
2408 WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart, PeriodicStart);
2409 WRITE_REGISTER_ULONG(&OperationalRegs->HcLSThreshold, LSThreshold);
2410
2411 /* Setup RhStatus register */
2412 RhStatus.AsULONG = 0;
2413 RhStatus.SetRemoteWakeupEnable = 1;
2414 RhStatus.SetGlobalPower = 1;
2415 WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG);
2416
2417 /* Setup RH PortStatus registers */
2418 RhDescriptorA = OHCI_ReadRhDescriptorA(OhciExtension);
2419 NumPorts = RhDescriptorA.NumberDownstreamPorts;
2420
2421 PortStatus.AsULONG = 0;
2422 PortStatus.SetPortPower = 1;
2423
2424 for (ix = 0; ix < NumPorts; ix++)
2425 {
2426 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[ix];
2427 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG);
2428 }
2429
2430 /* Restore HcControl register */
2431 ControlBak.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL;
2432 WRITE_REGISTER_ULONG(ControlReg, ControlBak.AsULONG);
2433
2434 /* Setup HcInterruptEnable register */
2435 IntEnable.AsULONG = 0xFFFFFFFF;
2436 IntEnable.Reserved1 = 0;
2437 WRITE_REGISTER_ULONG(InterruptEnableReg, IntEnable.AsULONG);
2438 }
2439
2440 MPSTATUS
2441 NTAPI
OHCI_StartSendOnePacket(IN PVOID ohciExtension,IN PVOID PacketParameters,IN PVOID Data,IN PULONG pDataLength,IN PVOID BufferVA,IN PVOID BufferPA,IN ULONG BufferLength,IN USBD_STATUS * pUSBDStatus)2442 OHCI_StartSendOnePacket(IN PVOID ohciExtension,
2443 IN PVOID PacketParameters,
2444 IN PVOID Data,
2445 IN PULONG pDataLength,
2446 IN PVOID BufferVA,
2447 IN PVOID BufferPA,
2448 IN ULONG BufferLength,
2449 IN USBD_STATUS * pUSBDStatus)
2450 {
2451 DPRINT1("OHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n");
2452 return MP_STATUS_SUCCESS;
2453 }
2454
2455 MPSTATUS
2456 NTAPI
OHCI_EndSendOnePacket(IN PVOID ohciExtension,IN PVOID PacketParameters,IN PVOID Data,IN PULONG pDataLength,IN PVOID BufferVA,IN PVOID BufferPA,IN ULONG BufferLength,IN USBD_STATUS * pUSBDStatus)2457 OHCI_EndSendOnePacket(IN PVOID ohciExtension,
2458 IN PVOID PacketParameters,
2459 IN PVOID Data,
2460 IN PULONG pDataLength,
2461 IN PVOID BufferVA,
2462 IN PVOID BufferPA,
2463 IN ULONG BufferLength,
2464 IN USBD_STATUS * pUSBDStatus)
2465 {
2466 DPRINT1("OHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n");
2467 return MP_STATUS_SUCCESS;
2468 }
2469
2470 MPSTATUS
2471 NTAPI
OHCI_PassThru(IN PVOID ohciExtension,IN PVOID passThruParameters,IN ULONG ParameterLength,IN PVOID pParameters)2472 OHCI_PassThru(IN PVOID ohciExtension,
2473 IN PVOID passThruParameters,
2474 IN ULONG ParameterLength,
2475 IN PVOID pParameters)
2476 {
2477 DPRINT1("OHCI_PassThru: UNIMPLEMENTED. FIXME\n");
2478 return MP_STATUS_SUCCESS;
2479 }
2480
2481 VOID
2482 NTAPI
OHCI_Unload(IN PDRIVER_OBJECT DriverObject)2483 OHCI_Unload(IN PDRIVER_OBJECT DriverObject)
2484 {
2485 #if DBG
2486 DPRINT1("OHCI_Unload: Not supported\n");
2487 #endif
2488 return;
2489 }
2490
2491 VOID
2492 NTAPI
OHCI_FlushInterrupts(IN PVOID uhciExtension)2493 OHCI_FlushInterrupts(IN PVOID uhciExtension)
2494 {
2495 #if DBG
2496 DPRINT1("OHCI_FlushInterrupts: Not supported\n");
2497 #endif
2498 return;
2499 }
2500
2501 NTSTATUS
2502 NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)2503 DriverEntry(IN PDRIVER_OBJECT DriverObject,
2504 IN PUNICODE_STRING RegistryPath)
2505 {
2506 NTSTATUS Status;
2507
2508 DPRINT_OHCI("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n",
2509 DriverObject,
2510 RegistryPath);
2511
2512 RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET));
2513
2514 RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_OHCI;
2515
2516 RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT |
2517 USB_MINIPORT_FLAGS_MEMORY_IO;
2518
2519 RegPacket.MiniPortBusBandwidth = TOTAL_USB11_BUS_BANDWIDTH;
2520
2521 RegPacket.MiniPortExtensionSize = sizeof(OHCI_EXTENSION);
2522 RegPacket.MiniPortEndpointSize = sizeof(OHCI_ENDPOINT);
2523 RegPacket.MiniPortTransferSize = sizeof(OHCI_TRANSFER);
2524 RegPacket.MiniPortResourcesSize = sizeof(OHCI_HC_RESOURCES);
2525
2526 RegPacket.OpenEndpoint = OHCI_OpenEndpoint;
2527 RegPacket.ReopenEndpoint = OHCI_ReopenEndpoint;
2528 RegPacket.QueryEndpointRequirements = OHCI_QueryEndpointRequirements;
2529 RegPacket.CloseEndpoint = OHCI_CloseEndpoint;
2530 RegPacket.StartController = OHCI_StartController;
2531 RegPacket.StopController = OHCI_StopController;
2532 RegPacket.SuspendController = OHCI_SuspendController;
2533 RegPacket.ResumeController = OHCI_ResumeController;
2534 RegPacket.InterruptService = OHCI_InterruptService;
2535 RegPacket.InterruptDpc = OHCI_InterruptDpc;
2536 RegPacket.SubmitTransfer = OHCI_SubmitTransfer;
2537 RegPacket.SubmitIsoTransfer = OHCI_SubmitIsoTransfer;
2538 RegPacket.AbortTransfer = OHCI_AbortTransfer;
2539 RegPacket.GetEndpointState = OHCI_GetEndpointState;
2540 RegPacket.SetEndpointState = OHCI_SetEndpointState;
2541 RegPacket.PollEndpoint = OHCI_PollEndpoint;
2542 RegPacket.CheckController = OHCI_CheckController;
2543 RegPacket.Get32BitFrameNumber = OHCI_Get32BitFrameNumber;
2544 RegPacket.InterruptNextSOF = OHCI_InterruptNextSOF;
2545 RegPacket.EnableInterrupts = OHCI_EnableInterrupts;
2546 RegPacket.DisableInterrupts = OHCI_DisableInterrupts;
2547 RegPacket.PollController = OHCI_PollController;
2548 RegPacket.SetEndpointDataToggle = OHCI_SetEndpointDataToggle;
2549 RegPacket.GetEndpointStatus = OHCI_GetEndpointStatus;
2550 RegPacket.SetEndpointStatus = OHCI_SetEndpointStatus;
2551 RegPacket.ResetController = OHCI_ResetController;
2552 RegPacket.RH_GetRootHubData = OHCI_RH_GetRootHubData;
2553 RegPacket.RH_GetStatus = OHCI_RH_GetStatus;
2554 RegPacket.RH_GetPortStatus = OHCI_RH_GetPortStatus;
2555 RegPacket.RH_GetHubStatus = OHCI_RH_GetHubStatus;
2556 RegPacket.RH_SetFeaturePortReset = OHCI_RH_SetFeaturePortReset;
2557 RegPacket.RH_SetFeaturePortPower = OHCI_RH_SetFeaturePortPower;
2558 RegPacket.RH_SetFeaturePortEnable = OHCI_RH_SetFeaturePortEnable;
2559 RegPacket.RH_SetFeaturePortSuspend = OHCI_RH_SetFeaturePortSuspend;
2560 RegPacket.RH_ClearFeaturePortEnable = OHCI_RH_ClearFeaturePortEnable;
2561 RegPacket.RH_ClearFeaturePortPower = OHCI_RH_ClearFeaturePortPower;
2562 RegPacket.RH_ClearFeaturePortSuspend = OHCI_RH_ClearFeaturePortSuspend;
2563 RegPacket.RH_ClearFeaturePortEnableChange = OHCI_RH_ClearFeaturePortEnableChange;
2564 RegPacket.RH_ClearFeaturePortConnectChange = OHCI_RH_ClearFeaturePortConnectChange;
2565 RegPacket.RH_ClearFeaturePortResetChange = OHCI_RH_ClearFeaturePortResetChange;
2566 RegPacket.RH_ClearFeaturePortSuspendChange = OHCI_RH_ClearFeaturePortSuspendChange;
2567 RegPacket.RH_ClearFeaturePortOvercurrentChange = OHCI_RH_ClearFeaturePortOvercurrentChange;
2568 RegPacket.RH_DisableIrq = OHCI_RH_DisableIrq;
2569 RegPacket.RH_EnableIrq = OHCI_RH_EnableIrq;
2570 RegPacket.StartSendOnePacket = OHCI_StartSendOnePacket;
2571 RegPacket.EndSendOnePacket = OHCI_EndSendOnePacket;
2572 RegPacket.PassThru = OHCI_PassThru;
2573 RegPacket.FlushInterrupts = OHCI_FlushInterrupts;
2574
2575 DriverObject->DriverUnload = OHCI_Unload;
2576
2577 Status = USBPORT_RegisterUSBPortDriver(DriverObject,
2578 USB10_MINIPORT_INTERFACE_VERSION,
2579 &RegPacket);
2580
2581 DPRINT_OHCI("DriverEntry: USBPORT_RegisterUSBPortDriver return Status - %x\n",
2582 Status);
2583
2584 return Status;
2585 }
2586