[USBEHCI_NEW] Bring-in the USB EHCI miniport driver created by Vadim Galyant. (#301)
[reactos.git] / drivers / usb / usbehci_new / usbehci.c
1 /*
2 * PROJECT: ReactOS USB EHCI Miniport Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: USBEHCI main driver functions
5 * COPYRIGHT: Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
6 */
7
8 #include "usbehci.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define NDEBUG_EHCI_TRACE
14 #include "dbg_ehci.h"
15
16 USBPORT_REGISTRATION_PACKET RegPacket;
17
18 static const UCHAR ClassicPeriod[8] = {
19 ENDPOINT_INTERRUPT_1ms - 1,
20 ENDPOINT_INTERRUPT_2ms - 1,
21 ENDPOINT_INTERRUPT_4ms - 1,
22 ENDPOINT_INTERRUPT_8ms - 1,
23 ENDPOINT_INTERRUPT_16ms - 1,
24 ENDPOINT_INTERRUPT_32ms - 1,
25 ENDPOINT_INTERRUPT_32ms - 1,
26 ENDPOINT_INTERRUPT_32ms - 1
27 };
28
29 static const EHCI_PERIOD pTable[] = {
30 { ENDPOINT_INTERRUPT_1ms, 0x00, 0xFF },
31 { ENDPOINT_INTERRUPT_2ms, 0x00, 0x55 },
32 { ENDPOINT_INTERRUPT_2ms, 0x00, 0xAA },
33 { ENDPOINT_INTERRUPT_4ms, 0x00, 0x11 },
34 { ENDPOINT_INTERRUPT_4ms, 0x00, 0x44 },
35 { ENDPOINT_INTERRUPT_4ms, 0x00, 0x22 },
36 { ENDPOINT_INTERRUPT_4ms, 0x00, 0x88 },
37 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x01 },
38 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x10 },
39 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x04 },
40 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x40 },
41 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x02 },
42 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x20 },
43 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x08 },
44 { ENDPOINT_INTERRUPT_8ms, 0x00, 0x80 },
45 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x01 },
46 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x01 },
47 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x10 },
48 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x10 },
49 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x04 },
50 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x04 },
51 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x40 },
52 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x40 },
53 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x02 },
54 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x02 },
55 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x20 },
56 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x20 },
57 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x08 },
58 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x08 },
59 { ENDPOINT_INTERRUPT_16ms, 0x01, 0x80 },
60 { ENDPOINT_INTERRUPT_16ms, 0x02, 0x80 },
61 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x01 },
62 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x01 },
63 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x01 },
64 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x01 },
65 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x10 },
66 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x10 },
67 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x10 },
68 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x10 },
69 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x04 },
70 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x04 },
71 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x04 },
72 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x04 },
73 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x40 },
74 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x40 },
75 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x40 },
76 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x40 },
77 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x02 },
78 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x02 },
79 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x02 },
80 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x02 },
81 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x20 },
82 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x20 },
83 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x20 },
84 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x20 },
85 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x08 },
86 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x08 },
87 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x08 },
88 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x08 },
89 { ENDPOINT_INTERRUPT_32ms, 0x03, 0x80 },
90 { ENDPOINT_INTERRUPT_32ms, 0x05, 0x80 },
91 { ENDPOINT_INTERRUPT_32ms, 0x04, 0x80 },
92 { ENDPOINT_INTERRUPT_32ms, 0x06, 0x80 },
93 { 0x00, 0x00, 0x00 }
94 };
95 C_ASSERT(RTL_NUMBER_OF(pTable) == INTERRUPT_ENDPOINTs + 1);
96
97 static const UCHAR Balance[] = {
98 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30,
99 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31
100 };
101 C_ASSERT(RTL_NUMBER_OF(Balance) == EHCI_FRAMES);
102
103 static const UCHAR LinkTable[] = {
104 255, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
105 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19,
106 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29,
107 30, 30, 0
108 };
109 C_ASSERT(RTL_NUMBER_OF(LinkTable) == INTERRUPT_ENDPOINTs + 1);
110
111 PEHCI_HCD_TD
112 NTAPI
113 EHCI_AllocTd(IN PEHCI_EXTENSION EhciExtension,
114 IN PEHCI_ENDPOINT EhciEndpoint)
115 {
116 PEHCI_HCD_TD TD;
117 ULONG ix;
118
119 DPRINT_EHCI("EHCI_AllocTd: ... \n");
120
121 if (EhciEndpoint->MaxTDs == 0)
122 {
123 RegPacket.UsbPortBugCheck(EhciExtension);
124 return NULL;
125 }
126
127 TD = EhciEndpoint->FirstTD;
128
129 for (ix = 1; TD->TdFlags & EHCI_HCD_TD_FLAG_ALLOCATED; ix++)
130 {
131 TD += 1;
132
133 if (ix >= EhciEndpoint->MaxTDs)
134 {
135 RegPacket.UsbPortBugCheck(EhciExtension);
136 return NULL;
137 }
138 }
139
140 TD->TdFlags |= EHCI_HCD_TD_FLAG_ALLOCATED;
141
142 EhciEndpoint->RemainTDs--;
143
144 return TD;
145 }
146
147 PEHCI_HCD_QH
148 NTAPI
149 EHCI_InitializeQH(IN PEHCI_EXTENSION EhciExtension,
150 IN PEHCI_ENDPOINT EhciEndpoint,
151 IN PEHCI_HCD_QH QH,
152 IN ULONG QhPA)
153 {
154 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
155 ULONG DeviceSpeed;
156
157 DPRINT_EHCI("EHCI_InitializeQH: EhciEndpoint - %p, QH - %p, QhPA - %p\n",
158 EhciEndpoint,
159 QH,
160 QhPA);
161
162 EndpointProperties = &EhciEndpoint->EndpointProperties;
163
164 RtlZeroMemory(QH, sizeof(EHCI_HCD_QH));
165
166 ASSERT((QhPA & ~LINK_POINTER_MASK) == 0);
167
168 QH->sqh.PhysicalAddress = QhPA;
169
170 QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress;
171 QH->sqh.HwQH.EndpointParams.EndpointNumber = EndpointProperties->EndpointAddress;
172
173 DeviceSpeed = EndpointProperties->DeviceSpeed;
174
175 switch (DeviceSpeed)
176 {
177 case UsbLowSpeed:
178 QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_LOW_SPEED;
179 break;
180
181 case UsbFullSpeed:
182 QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_FULL_SPEED;
183 break;
184
185 case UsbHighSpeed:
186 QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_HIGH_SPEED;
187 break;
188
189 default:
190 DPRINT1("EHCI_InitializeQH: Unknown DeviceSpeed - %x\n", DeviceSpeed);
191 ASSERT(FALSE);
192 break;
193 }
194
195 QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize;
196 QH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1;
197
198 if (DeviceSpeed == UsbHighSpeed)
199 {
200 QH->sqh.HwQH.EndpointCaps.HubAddr = 0;
201 QH->sqh.HwQH.EndpointCaps.PortNumber = 0;
202 }
203 else
204 {
205 QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr;
206 QH->sqh.HwQH.EndpointCaps.PortNumber = EndpointProperties->PortNumber;
207
208 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
209 QH->sqh.HwQH.EndpointParams.ControlEndpointFlag = 1;
210 }
211
212 QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
213 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
214
215 QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
216 EHCI_TOKEN_STATUS_HALTED);
217
218 return QH;
219 }
220
221 MPSTATUS
222 NTAPI
223 EHCI_OpenBulkOrControlEndpoint(IN PEHCI_EXTENSION EhciExtension,
224 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
225 IN PEHCI_ENDPOINT EhciEndpoint,
226 IN BOOLEAN IsControl)
227 {
228 PEHCI_HCD_QH QH;
229 ULONG QhPA;
230 PEHCI_HCD_TD TdVA;
231 ULONG TdPA;
232 PEHCI_HCD_TD TD;
233 ULONG TdCount;
234 ULONG ix;
235
236 DPRINT("EHCI_OpenBulkOrControlEndpoint: EhciEndpoint - %p, IsControl - %x\n",
237 EhciEndpoint,
238 IsControl);
239
240 InitializeListHead(&EhciEndpoint->ListTDs);
241
242 EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA;
243 EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA;
244
245 RtlZeroMemory(EhciEndpoint->DmaBufferVA, sizeof(EHCI_HCD_TD));
246
247 QH = (PEHCI_HCD_QH)EhciEndpoint->DmaBufferVA + 1;
248 QhPA = EhciEndpoint->DmaBufferPA + sizeof(EHCI_HCD_TD);
249
250 EhciEndpoint->FirstTD = (PEHCI_HCD_TD)(QH + 1);
251
252 TdCount = (EndpointProperties->BufferLength -
253 (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) /
254 sizeof(EHCI_HCD_TD);
255
256 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
257 EhciEndpoint->EndpointStatus |= USBPORT_ENDPOINT_CONTROL;
258
259 EhciEndpoint->MaxTDs = TdCount;
260 EhciEndpoint->RemainTDs = TdCount;
261
262 TdVA = EhciEndpoint->FirstTD;
263 TdPA = QhPA + sizeof(EHCI_HCD_QH);
264
265 for (ix = 0; ix < TdCount; ix++)
266 {
267 DPRINT_EHCI("EHCI_OpenBulkOrControlEndpoint: TdVA - %p, TdPA - %p\n",
268 TdVA,
269 TdPA);
270
271 RtlZeroMemory(TdVA, sizeof(EHCI_HCD_TD));
272
273 ASSERT((TdPA & ~LINK_POINTER_MASK) == 0);
274
275 TdVA->PhysicalAddress = TdPA;
276 TdVA->EhciEndpoint = EhciEndpoint;
277 TdVA->EhciTransfer = NULL;
278
279 TdPA += sizeof(EHCI_HCD_TD);
280 TdVA += 1;
281 }
282
283 EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension,
284 EhciEndpoint,
285 QH,
286 QhPA);
287
288 if (IsControl)
289 {
290 QH->sqh.HwQH.EndpointParams.DataToggleControl = 1;
291 EhciEndpoint->HcdHeadP = NULL;
292 }
293 else
294 {
295 QH->sqh.HwQH.EndpointParams.DataToggleControl = 0;
296 }
297
298 TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
299
300 if (!TD)
301 return MP_STATUS_NO_RESOURCES;
302
303 TD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY;
304 TD->HwTD.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
305
306 TD->HwTD.NextTD = TERMINATE_POINTER;
307 TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
308
309 TD->NextHcdTD = NULL;
310 TD->AltNextHcdTD = NULL;
311
312 EhciEndpoint->HcdTailP = TD;
313 EhciEndpoint->HcdHeadP = TD;
314
315 QH->sqh.HwQH.CurrentTD = TD->PhysicalAddress;
316 QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
317 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
318
319 QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
320 QH->sqh.HwQH.Token.TransferBytes = 0;
321
322 return MP_STATUS_SUCCESS;
323 }
324
325 MPSTATUS
326 NTAPI
327 EHCI_OpenInterruptEndpoint(IN PEHCI_EXTENSION EhciExtension,
328 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
329 IN PEHCI_ENDPOINT EhciEndpoint)
330 {
331 PEHCI_HCD_QH QH;
332 ULONG QhPA;
333 PEHCI_HCD_TD FirstTD;
334 ULONG FirstTdPA;
335 PEHCI_HCD_TD TD;
336 PEHCI_HCD_TD DummyTD;
337 ULONG TdCount;
338 ULONG ix;
339 const EHCI_PERIOD * PeriodTable = NULL;
340 ULONG ScheduleOffset;
341 ULONG Idx = 0;
342 UCHAR Period;
343
344 DPRINT("EHCI_OpenInterruptEndpoint: EhciExtension - %p, EndpointProperties - %p, EhciEndpoint - %p\n",
345 EhciExtension,
346 EndpointProperties,
347 EhciEndpoint);
348
349 Period = EndpointProperties->Period;
350 ScheduleOffset = EndpointProperties->ScheduleOffset;
351
352 ASSERT(Period < (INTERRUPT_ENDPOINTs + 1));
353
354 while (!(Period & 1))
355 {
356 Idx++;
357 Period >>= 1;
358 }
359
360 ASSERT(Idx < 8);
361
362 InitializeListHead(&EhciEndpoint->ListTDs);
363
364 if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
365 {
366 PeriodTable = &pTable[ClassicPeriod[Idx] + ScheduleOffset];
367 EhciEndpoint->PeriodTable = PeriodTable;
368
369 DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, ScheduleMask - %X, Index - %X\n",
370 EhciEndpoint,
371 PeriodTable->ScheduleMask,
372 ClassicPeriod[Idx]);
373
374 EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[PeriodTable->PeriodIdx];
375 }
376 else
377 {
378 EhciEndpoint->PeriodTable = NULL;
379
380 DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, Index - %X\n",
381 EhciEndpoint,
382 ClassicPeriod[Idx]);
383
384 EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[ClassicPeriod[Idx] +
385 ScheduleOffset];
386 }
387
388 EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA;
389 EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA;
390
391 RtlZeroMemory((PVOID)EndpointProperties->BufferVA, sizeof(EHCI_HCD_TD));
392
393 QH = (PEHCI_HCD_QH)(EndpointProperties->BufferVA + sizeof(EHCI_HCD_TD));
394 QhPA = EndpointProperties->BufferPA + sizeof(EHCI_HCD_TD);
395
396 FirstTD = (PEHCI_HCD_TD)(EndpointProperties->BufferVA +
397 sizeof(EHCI_HCD_TD) +
398 sizeof(EHCI_HCD_QH));
399
400 FirstTdPA = EndpointProperties->BufferPA +
401 sizeof(EHCI_HCD_TD) +
402 sizeof(EHCI_HCD_QH);
403
404 TdCount = (EndpointProperties->BufferLength -
405 (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) /
406 sizeof(EHCI_HCD_TD);
407
408 ASSERT(TdCount >= EHCI_MAX_INTERRUPT_TD_COUNT + 1);
409
410 EhciEndpoint->FirstTD = FirstTD;
411 EhciEndpoint->MaxTDs = TdCount;
412
413 for (ix = 0; ix < TdCount; ix++)
414 {
415 TD = EhciEndpoint->FirstTD + ix;
416
417 RtlZeroMemory(TD, sizeof(EHCI_HCD_TD));
418
419 ASSERT((FirstTdPA & ~LINK_POINTER_MASK) == 0);
420
421 TD->PhysicalAddress = FirstTdPA;
422 TD->EhciEndpoint = EhciEndpoint;
423 TD->EhciTransfer = NULL;
424
425 FirstTdPA += sizeof(EHCI_HCD_TD);
426 }
427
428 EhciEndpoint->RemainTDs = TdCount;
429
430 EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension,
431 EhciEndpoint,
432 QH,
433 QhPA);
434
435 if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
436 {
437 QH->sqh.HwQH.EndpointCaps.InterruptMask = PeriodTable->ScheduleMask;
438 }
439 else
440 {
441 QH->sqh.HwQH.EndpointCaps.InterruptMask =
442 EndpointProperties->InterruptScheduleMask;
443
444 QH->sqh.HwQH.EndpointCaps.SplitCompletionMask =
445 EndpointProperties->SplitCompletionMask;
446 }
447
448 DummyTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
449
450 DummyTD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY;
451 DummyTD->NextHcdTD = NULL;
452 DummyTD->AltNextHcdTD = NULL;
453
454 DummyTD->HwTD.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE;
455
456 DummyTD->HwTD.NextTD = TERMINATE_POINTER;
457 DummyTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
458
459 EhciEndpoint->HcdTailP = DummyTD;
460 EhciEndpoint->HcdHeadP = DummyTD;
461
462 QH->sqh.HwQH.CurrentTD = DummyTD->PhysicalAddress;
463 QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
464 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
465
466 QH->sqh.HwQH.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE;
467 QH->sqh.HwQH.Token.TransferBytes = 0;
468
469 return MP_STATUS_SUCCESS;
470 }
471
472 MPSTATUS
473 NTAPI
474 EHCI_OpenHsIsoEndpoint(IN PEHCI_EXTENSION EhciExtension,
475 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
476 IN PEHCI_ENDPOINT EhciEndpoint)
477 {
478 DPRINT1("EHCI_OpenHsIsoEndpoint: UNIMPLEMENTED. FIXME\n");
479 return MP_STATUS_NOT_SUPPORTED;
480 }
481
482 MPSTATUS
483 NTAPI
484 EHCI_OpenIsoEndpoint(IN PEHCI_EXTENSION EhciExtension,
485 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
486 IN PEHCI_ENDPOINT EhciEndpoint)
487 {
488 DPRINT1("EHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n");
489 return MP_STATUS_NOT_SUPPORTED;
490 }
491
492 MPSTATUS
493 NTAPI
494 EHCI_OpenEndpoint(IN PVOID ehciExtension,
495 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
496 IN PVOID ehciEndpoint)
497 {
498 PEHCI_EXTENSION EhciExtension = ehciExtension;
499 PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
500 ULONG TransferType;
501 MPSTATUS MPStatus;
502
503 DPRINT("EHCI_OpenEndpoint: ... \n");
504
505 RtlCopyMemory(&EhciEndpoint->EndpointProperties,
506 EndpointProperties,
507 sizeof(EhciEndpoint->EndpointProperties));
508
509 TransferType = EndpointProperties->TransferType;
510
511 switch (TransferType)
512 {
513 case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
514 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
515 {
516 MPStatus = EHCI_OpenHsIsoEndpoint(EhciExtension,
517 EndpointProperties,
518 EhciEndpoint);
519 }
520 else
521 {
522 MPStatus = EHCI_OpenIsoEndpoint(EhciExtension,
523 EndpointProperties,
524 EhciEndpoint);
525 }
526
527 break;
528
529 case USBPORT_TRANSFER_TYPE_CONTROL:
530 MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension,
531 EndpointProperties,
532 EhciEndpoint,
533 TRUE);
534 break;
535
536 case USBPORT_TRANSFER_TYPE_BULK:
537 MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension,
538 EndpointProperties,
539 EhciEndpoint,
540 FALSE);
541 break;
542
543 case USBPORT_TRANSFER_TYPE_INTERRUPT:
544 MPStatus = EHCI_OpenInterruptEndpoint(EhciExtension,
545 EndpointProperties,
546 EhciEndpoint);
547 break;
548
549 default:
550 MPStatus = MP_STATUS_NOT_SUPPORTED;
551 break;
552 }
553
554 return MPStatus;
555 }
556
557 MPSTATUS
558 NTAPI
559 EHCI_ReopenEndpoint(IN PVOID ehciExtension,
560 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
561 IN PVOID ehciEndpoint)
562 {
563 PEHCI_ENDPOINT EhciEndpoint;
564 ULONG TransferType;
565 PEHCI_HCD_QH QH;
566 MPSTATUS MPStatus;
567
568 EhciEndpoint = ehciEndpoint;
569
570 TransferType = EndpointProperties->TransferType;
571
572 DPRINT("EHCI_ReopenEndpoint: EhciEndpoint - %p, TransferType - %x\n",
573 EhciEndpoint,
574 TransferType);
575
576 switch (TransferType)
577 {
578 case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
579 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
580 {
581 DPRINT1("EHCI_ReopenEndpoint: HS Iso. UNIMPLEMENTED. FIXME\n");
582 MPStatus = MP_STATUS_NOT_SUPPORTED;
583 }
584 else
585 {
586 DPRINT1("EHCI_ReopenEndpoint: Iso. UNIMPLEMENTED. FIXME\n");
587 MPStatus = MP_STATUS_NOT_SUPPORTED;
588 }
589
590 break;
591
592 case USBPORT_TRANSFER_TYPE_CONTROL:
593 case USBPORT_TRANSFER_TYPE_BULK:
594 case USBPORT_TRANSFER_TYPE_INTERRUPT:
595 RtlCopyMemory(&EhciEndpoint->EndpointProperties,
596 EndpointProperties,
597 sizeof(EhciEndpoint->EndpointProperties));
598
599 QH = EhciEndpoint->QH;
600
601 QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress;
602 QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize;
603
604 QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr;
605
606 break;
607
608 default:
609 DPRINT1("EHCI_ReopenEndpoint: Unknown TransferType\n");
610 MPStatus = MP_STATUS_SUCCESS;
611 break;
612 }
613
614 return MPStatus;
615 }
616
617 VOID
618 NTAPI
619 EHCI_QueryEndpointRequirements(IN PVOID ehciExtension,
620 IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties,
621 IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements)
622 {
623 ULONG TransferType;
624
625 DPRINT("EHCI_QueryEndpointRequirements: ... \n");
626
627 TransferType = EndpointProperties->TransferType;
628
629 switch (TransferType)
630 {
631 case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
632 DPRINT("EHCI_QueryEndpointRequirements: IsoTransfer\n");
633
634 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
635 {
636 EndpointRequirements->HeaderBufferSize = EHCI_MAX_HS_ISO_HEADER_BUFFER_SIZE;
637 EndpointRequirements->MaxTransferSize = EHCI_MAX_HS_ISO_TRANSFER_SIZE;
638 }
639 else
640 {
641 EndpointRequirements->HeaderBufferSize = EHCI_MAX_FS_ISO_HEADER_BUFFER_SIZE;
642 EndpointRequirements->MaxTransferSize = EHCI_MAX_FS_ISO_TRANSFER_SIZE;
643 }
644 break;
645
646 case USBPORT_TRANSFER_TYPE_CONTROL:
647 DPRINT("EHCI_QueryEndpointRequirements: ControlTransfer\n");
648 EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
649 sizeof(EHCI_HCD_QH) +
650 EHCI_MAX_CONTROL_TD_COUNT * sizeof(EHCI_HCD_TD);
651
652 EndpointRequirements->MaxTransferSize = EHCI_MAX_CONTROL_TRANSFER_SIZE;
653 break;
654
655 case USBPORT_TRANSFER_TYPE_BULK:
656 DPRINT("EHCI_QueryEndpointRequirements: BulkTransfer\n");
657 EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
658 sizeof(EHCI_HCD_QH) +
659 EHCI_MAX_BULK_TD_COUNT * sizeof(EHCI_HCD_TD);
660
661 EndpointRequirements->MaxTransferSize = EHCI_MAX_BULK_TRANSFER_SIZE;
662 break;
663
664 case USBPORT_TRANSFER_TYPE_INTERRUPT:
665 DPRINT("EHCI_QueryEndpointRequirements: InterruptTransfer\n");
666 EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) +
667 sizeof(EHCI_HCD_QH) +
668 EHCI_MAX_INTERRUPT_TD_COUNT * sizeof(EHCI_HCD_TD);
669
670 EndpointRequirements->MaxTransferSize = EHCI_MAX_INTERRUPT_TRANSFER_SIZE;
671 break;
672
673 default:
674 DPRINT1("EHCI_QueryEndpointRequirements: Unknown TransferType - %x\n",
675 TransferType);
676 DbgBreakPoint();
677 break;
678 }
679 }
680
681 VOID
682 NTAPI
683 EHCI_DisablePeriodicList(IN PEHCI_EXTENSION EhciExtension)
684 {
685 PEHCI_HW_REGISTERS OperationalRegs;
686 EHCI_USB_COMMAND Command;
687
688 DPRINT("EHCI_DisablePeriodicList: ... \n");
689
690 if (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT)
691 {
692 OperationalRegs = EhciExtension->OperationalRegs;
693
694 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
695 Command.PeriodicEnable = 0;
696 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
697 }
698 }
699
700 VOID
701 NTAPI
702 EHCI_CloseEndpoint(IN PVOID ehciExtension,
703 IN PVOID ehciEndpoint,
704 IN BOOLEAN DisablePeriodic)
705 {
706 PEHCI_EXTENSION EhciExtension = ehciExtension;
707 PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
708 ULONG TransferType;
709
710 DPRINT1("EHCI_CloseEndpoint: EhciEndpoint - %p, DisablePeriodic - %X\n",
711 EhciEndpoint,
712 DisablePeriodic);
713
714 if (DisablePeriodic)
715 {
716 TransferType = EhciEndpoint->EndpointProperties.TransferType;
717
718 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS ||
719 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
720 {
721 EHCI_DisablePeriodicList(EhciExtension);
722 }
723 }
724 }
725
726 PEHCI_STATIC_QH
727 NTAPI
728 EHCI_GetQhForFrame(IN PEHCI_EXTENSION EhciExtension,
729 IN ULONG FrameIdx)
730 {
731 //DPRINT_EHCI("EHCI_GetQhForFrame: FrameIdx - %x, Balance[FrameIdx] - %x\n",
732 // FrameIdx,
733 // Balance[FrameIdx & 0x1F]);
734
735 return EhciExtension->PeriodicHead[Balance[FrameIdx & (EHCI_FRAMES - 1)]];
736 }
737
738 PEHCI_HCD_QH
739 NTAPI
740 EHCI_GetDummyQhForFrame(IN PEHCI_EXTENSION EhciExtension,
741 IN ULONG Idx)
742 {
743 return (PEHCI_HCD_QH)((ULONG_PTR)EhciExtension->IsoDummyQHListVA +
744 Idx * sizeof(EHCI_HCD_QH));
745 }
746
747 VOID
748 NTAPI
749 EHCI_AlignHwStructure(IN PEHCI_EXTENSION EhciExtension,
750 IN PULONG PhysicalAddress,
751 IN PULONG_PTR VirtualAddress,
752 IN ULONG Alignment)
753 {
754 ULONG PAddress;
755 ULONG NewPAddress;
756 ULONG_PTR VAddress;
757
758 //DPRINT_EHCI("EHCI_AlignHwStructure: *PhysicalAddress - %X, *VirtualAddress - %X, Alignment - %x\n",
759 // *PhysicalAddress,
760 // *VirtualAddress,
761 // Alignment);
762
763 PAddress = *PhysicalAddress;
764 VAddress = *VirtualAddress;
765
766 NewPAddress = (ULONG)(ULONG_PTR)PAGE_ALIGN(*PhysicalAddress + Alignment - 1);
767
768 if (NewPAddress != (ULONG)(ULONG_PTR)PAGE_ALIGN(*PhysicalAddress))
769 {
770 VAddress += NewPAddress - PAddress;
771 PAddress = NewPAddress;
772
773 DPRINT("EHCI_AlignHwStructure: VAddress - %X, PAddress - %X\n",
774 VAddress,
775 PAddress);
776 }
777
778 *VirtualAddress = VAddress;
779 *PhysicalAddress = PAddress;
780 }
781
782 VOID
783 NTAPI
784 EHCI_AddDummyQHs(IN PEHCI_EXTENSION EhciExtension)
785 {
786 PEHCI_HC_RESOURCES HcResourcesVA;
787 PEHCI_HCD_QH DummyQH;
788 ULONG DummyQhPA;
789 EHCI_QH_EP_PARAMS EndpointParams;
790 EHCI_LINK_POINTER PAddress;
791 ULONG Frame;
792
793 DPRINT("EHCI_AddDummyQueueHeads: EhciExtension - %p\n", EhciExtension);
794
795 HcResourcesVA = EhciExtension->HcResourcesVA;
796
797 DummyQH = EhciExtension->IsoDummyQHListVA;
798 DummyQhPA = EhciExtension->IsoDummyQHListPA;
799
800 for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++)
801 {
802 RtlZeroMemory(DummyQH, sizeof(EHCI_HCD_QH));
803
804 PAddress.AsULONG = HcResourcesVA->PeriodicFrameList[Frame];
805
806 DummyQH->sqh.HwQH.HorizontalLink.AsULONG = PAddress.AsULONG;
807 DummyQH->sqh.HwQH.CurrentTD = 0;
808 DummyQH->sqh.HwQH.NextTD = TERMINATE_POINTER;
809 DummyQH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
810
811 EndpointParams = DummyQH->sqh.HwQH.EndpointParams;
812 EndpointParams.DeviceAddress = 0;
813 EndpointParams.EndpointSpeed = 0;
814 EndpointParams.MaximumPacketLength = EHCI_DUMMYQH_MAX_PACKET_LENGTH;
815 DummyQH->sqh.HwQH.EndpointParams = EndpointParams;
816
817 DummyQH->sqh.HwQH.EndpointCaps.AsULONG = 0;
818 DummyQH->sqh.HwQH.EndpointCaps.InterruptMask = 0;
819 DummyQH->sqh.HwQH.EndpointCaps.SplitCompletionMask = 0;
820 DummyQH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1;
821
822 DummyQH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
823
824 DummyQH->sqh.PhysicalAddress = DummyQhPA;
825 DummyQH->sqh.StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame);
826
827 PAddress.AsULONG = DummyQhPA;
828 PAddress.Reserved = 0;
829 PAddress.Type = EHCI_LINK_TYPE_QH;
830
831 HcResourcesVA->PeriodicFrameList[Frame] = PAddress.AsULONG;
832
833 DummyQH++;
834 DummyQhPA += sizeof(EHCI_HCD_QH);
835 }
836 }
837
838 VOID
839 NTAPI
840 EHCI_InitializeInterruptSchedule(IN PEHCI_EXTENSION EhciExtension)
841 {
842 PEHCI_STATIC_QH StaticQH;
843 ULONG ix;
844
845 DPRINT("EHCI_InitializeInterruptSchedule: ... \n");
846
847 for (ix = 0; ix < INTERRUPT_ENDPOINTs; ix++)
848 {
849 StaticQH = EhciExtension->PeriodicHead[ix];
850
851 StaticQH->HwQH.EndpointParams.HeadReclamationListFlag = 0;
852 StaticQH->HwQH.NextTD |= TERMINATE_POINTER;
853 StaticQH->HwQH.Token.Status |= (UCHAR)EHCI_TOKEN_STATUS_HALTED;
854 }
855
856 for (ix = 1; ix < INTERRUPT_ENDPOINTs; ix++)
857 {
858 StaticQH = EhciExtension->PeriodicHead[ix];
859
860 StaticQH->PrevHead = NULL;
861 StaticQH->NextHead = (PEHCI_HCD_QH)EhciExtension->PeriodicHead[LinkTable[ix]];
862
863 StaticQH->HwQH.HorizontalLink.AsULONG =
864 EhciExtension->PeriodicHead[LinkTable[ix]]->PhysicalAddress;
865
866 StaticQH->HwQH.HorizontalLink.Type = EHCI_LINK_TYPE_QH;
867 StaticQH->HwQH.EndpointCaps.InterruptMask = 0xFF;
868
869 StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC;
870
871 if (ix < (ENDPOINT_INTERRUPT_8ms - 1))
872 StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC_FAST;
873 }
874
875 EhciExtension->PeriodicHead[0]->HwQH.HorizontalLink.Terminate = 1;
876
877 EhciExtension->PeriodicHead[0]->QhFlags |= (EHCI_QH_FLAG_STATIC |
878 EHCI_QH_FLAG_STATIC_FAST);
879 }
880
881 MPSTATUS
882 NTAPI
883 EHCI_InitializeSchedule(IN PEHCI_EXTENSION EhciExtension,
884 IN ULONG_PTR BaseVA,
885 IN ULONG BasePA)
886 {
887 PEHCI_HW_REGISTERS OperationalRegs;
888 PEHCI_HC_RESOURCES HcResourcesVA;
889 ULONG HcResourcesPA;
890 PEHCI_STATIC_QH AsyncHead;
891 ULONG AsyncHeadPA;
892 PEHCI_STATIC_QH PeriodicHead;
893 ULONG PeriodicHeadPA;
894 PEHCI_STATIC_QH StaticQH;
895 EHCI_LINK_POINTER NextLink;
896 EHCI_LINK_POINTER StaticHeadPA;
897 ULONG Frame;
898 ULONG ix;
899
900 DPRINT("EHCI_InitializeSchedule: BaseVA - %p, BasePA - %p\n",
901 BaseVA,
902 BasePA);
903
904 OperationalRegs = EhciExtension->OperationalRegs;
905
906 HcResourcesVA = (PEHCI_HC_RESOURCES)BaseVA;
907 HcResourcesPA = BasePA;
908
909 EhciExtension->HcResourcesVA = HcResourcesVA;
910 EhciExtension->HcResourcesPA = BasePA;
911
912 /* Asynchronous Schedule */
913
914 AsyncHead = &HcResourcesVA->AsyncHead;
915 AsyncHeadPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, AsyncHead);
916
917 RtlZeroMemory(AsyncHead, sizeof(EHCI_STATIC_QH));
918
919 NextLink.AsULONG = AsyncHeadPA;
920 NextLink.Type = EHCI_LINK_TYPE_QH;
921
922 AsyncHead->HwQH.HorizontalLink = NextLink;
923 AsyncHead->HwQH.EndpointParams.HeadReclamationListFlag = 1;
924 AsyncHead->HwQH.EndpointCaps.PipeMultiplier = 1;
925 AsyncHead->HwQH.NextTD |= TERMINATE_POINTER;
926 AsyncHead->HwQH.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_HALTED;
927
928 AsyncHead->PhysicalAddress = AsyncHeadPA;
929 AsyncHead->PrevHead = AsyncHead->NextHead = (PEHCI_HCD_QH)AsyncHead;
930
931 EhciExtension->AsyncHead = AsyncHead;
932
933 /* Periodic Schedule */
934
935 PeriodicHead = &HcResourcesVA->PeriodicHead[0];
936 PeriodicHeadPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, PeriodicHead[0]);
937
938 for (ix = 0; ix < (INTERRUPT_ENDPOINTs + 1); ix++)
939 {
940 EHCI_AlignHwStructure(EhciExtension,
941 &PeriodicHeadPA,
942 (PULONG_PTR)&PeriodicHead,
943 80);
944
945 EhciExtension->PeriodicHead[ix] = PeriodicHead;
946 EhciExtension->PeriodicHead[ix]->PhysicalAddress = PeriodicHeadPA;
947
948 PeriodicHead += 1;
949 PeriodicHeadPA += sizeof(EHCI_STATIC_QH);
950 }
951
952 EHCI_InitializeInterruptSchedule(EhciExtension);
953
954 for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++)
955 {
956 StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame);
957
958 StaticHeadPA.AsULONG = StaticQH->PhysicalAddress;
959 StaticHeadPA.Type = EHCI_LINK_TYPE_QH;
960
961 //DPRINT_EHCI("EHCI_InitializeSchedule: StaticHeadPA[%x] - %X\n",
962 // Frame,
963 // StaticHeadPA);
964
965 HcResourcesVA->PeriodicFrameList[Frame] = StaticHeadPA.AsULONG;
966 }
967
968 EhciExtension->IsoDummyQHListVA = &HcResourcesVA->IsoDummyQH[0];
969 EhciExtension->IsoDummyQHListPA = HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, IsoDummyQH[0]);
970
971 EHCI_AddDummyQHs(EhciExtension);
972
973 WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase,
974 EhciExtension->HcResourcesPA + FIELD_OFFSET(EHCI_HC_RESOURCES, PeriodicFrameList));
975
976 WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase,
977 NextLink.AsULONG);
978
979 return MP_STATUS_SUCCESS;
980 }
981
982 MPSTATUS
983 NTAPI
984 EHCI_InitializeHardware(IN PEHCI_EXTENSION EhciExtension)
985 {
986 PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters;
987 PEHCI_HW_REGISTERS OperationalRegs;
988 EHCI_USB_COMMAND Command;
989 LARGE_INTEGER EndTime;
990 LARGE_INTEGER CurrentTime;
991 EHCI_HC_STRUCTURAL_PARAMS StructuralParams;
992
993 DPRINT("EHCI_InitializeHardware: ... \n");
994
995 OperationalRegs = EhciExtension->OperationalRegs;
996 CapabilityRegisters = EhciExtension->CapabilityRegisters;
997
998 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
999 Command.Reset = 1;
1000 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1001
1002 KeQuerySystemTime(&EndTime);
1003 EndTime.QuadPart += 100 * 10000; // 100 msec
1004
1005 DPRINT("EHCI_InitializeHardware: Start reset ... \n");
1006
1007 while (TRUE)
1008 {
1009 KeQuerySystemTime(&CurrentTime);
1010 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1011
1012 if (Command.Reset != 1)
1013 break;
1014
1015 if (CurrentTime.QuadPart >= EndTime.QuadPart)
1016 {
1017 if (Command.Reset == 1)
1018 {
1019 DPRINT1("EHCI_InitializeHardware: Reset failed!\n");
1020 return MP_STATUS_HW_ERROR;
1021 }
1022
1023 break;
1024 }
1025 }
1026
1027 DPRINT("EHCI_InitializeHardware: Reset - OK\n");
1028
1029 StructuralParams.AsULONG = READ_REGISTER_ULONG(&CapabilityRegisters->StructParameters.AsULONG);
1030
1031 EhciExtension->NumberOfPorts = StructuralParams.PortCount;
1032 EhciExtension->PortPowerControl = StructuralParams.PortPowerControl;
1033
1034 DPRINT("EHCI_InitializeHardware: StructuralParams - %X\n", StructuralParams.AsULONG);
1035 DPRINT("EHCI_InitializeHardware: PortPowerControl - %x\n", EhciExtension->PortPowerControl);
1036 DPRINT("EHCI_InitializeHardware: N_PORTS - %x\n", EhciExtension->NumberOfPorts);
1037
1038 WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase, 0);
1039 WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase, 0);
1040
1041 EhciExtension->InterruptMask.AsULONG = 0;
1042 EhciExtension->InterruptMask.Interrupt = 1;
1043 EhciExtension->InterruptMask.ErrorInterrupt = 1;
1044 EhciExtension->InterruptMask.PortChangeInterrupt = 0;
1045 EhciExtension->InterruptMask.FrameListRollover = 1;
1046 EhciExtension->InterruptMask.HostSystemError = 1;
1047 EhciExtension->InterruptMask.InterruptOnAsyncAdvance = 1;
1048
1049 return MP_STATUS_SUCCESS;
1050 }
1051
1052 UCHAR
1053 NTAPI
1054 EHCI_GetOffsetEECP(IN PEHCI_EXTENSION EhciExtension,
1055 IN UCHAR CapabilityID)
1056 {
1057 EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability;
1058 EHCI_HC_CAPABILITY_PARAMS CapParameters;
1059 UCHAR OffsetEECP;
1060
1061 DPRINT("EHCI_GetOffsetEECP: CapabilityID - %x\n", CapabilityID);
1062
1063 CapParameters = EhciExtension->CapabilityRegisters->CapParameters;
1064
1065 OffsetEECP = CapParameters.ExtCapabilitiesPointer;
1066
1067 if (!OffsetEECP)
1068 return 0;
1069
1070 while (TRUE)
1071 {
1072 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1073 TRUE,
1074 &LegacyCapability.AsULONG,
1075 OffsetEECP,
1076 sizeof(LegacyCapability));
1077
1078 DPRINT("EHCI_GetOffsetEECP: OffsetEECP - %x\n", OffsetEECP);
1079
1080 if (LegacyCapability.CapabilityID == CapabilityID)
1081 break;
1082
1083 OffsetEECP = LegacyCapability.NextCapabilityPointer;
1084
1085 if (!OffsetEECP)
1086 return 0;
1087 }
1088
1089 return OffsetEECP;
1090 }
1091
1092 MPSTATUS
1093 NTAPI
1094 EHCI_TakeControlHC(IN PEHCI_EXTENSION EhciExtension)
1095 {
1096 LARGE_INTEGER EndTime;
1097 LARGE_INTEGER CurrentTime;
1098 EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability;
1099 UCHAR OffsetEECP;
1100
1101 DPRINT("EHCI_TakeControlHC: EhciExtension - %p\n", EhciExtension);
1102
1103 OffsetEECP = EHCI_GetOffsetEECP(EhciExtension, 1);
1104
1105 if (OffsetEECP == 0)
1106 return MP_STATUS_SUCCESS;
1107
1108 DPRINT("EHCI_TakeControlHC: OffsetEECP - %X\n", OffsetEECP);
1109
1110 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1111 TRUE,
1112 &LegacyCapability.AsULONG,
1113 OffsetEECP,
1114 sizeof(LegacyCapability));
1115
1116 if (LegacyCapability.BiosOwnedSemaphore == 0)
1117 return MP_STATUS_SUCCESS;
1118
1119 LegacyCapability.OsOwnedSemaphore = 1;
1120
1121 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1122 FALSE,
1123 &LegacyCapability.AsULONG,
1124 OffsetEECP,
1125 sizeof(LegacyCapability));
1126
1127 KeQuerySystemTime(&EndTime);
1128 EndTime.QuadPart += 100 * 10000;
1129
1130 do
1131 {
1132 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1133 TRUE,
1134 &LegacyCapability.AsULONG,
1135 OffsetEECP,
1136 sizeof(LegacyCapability));
1137 KeQuerySystemTime(&CurrentTime);
1138
1139 if (LegacyCapability.BiosOwnedSemaphore)
1140 {
1141 DPRINT("EHCI_TakeControlHC: Ownership is ok\n");
1142 break;
1143 }
1144 }
1145 while (CurrentTime.QuadPart <= EndTime.QuadPart);
1146
1147 return MP_STATUS_SUCCESS;
1148 }
1149
1150 VOID
1151 NTAPI
1152 EHCI_GetRegistryParameters(IN PEHCI_EXTENSION EhciExtension)
1153 {
1154 DPRINT1("EHCI_GetRegistryParameters: UNIMPLEMENTED. FIXME\n");
1155 }
1156
1157 MPSTATUS
1158 NTAPI
1159 EHCI_StartController(IN PVOID ehciExtension,
1160 IN PUSBPORT_RESOURCES Resources)
1161 {
1162 PEHCI_EXTENSION EhciExtension = ehciExtension;
1163 PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters;
1164 PEHCI_HW_REGISTERS OperationalRegs;
1165 MPSTATUS MPStatus;
1166 EHCI_USB_COMMAND Command;
1167 UCHAR CapabilityRegLength;
1168 UCHAR Fladj;
1169
1170 DPRINT("EHCI_StartController: ... \n");
1171
1172 if ((Resources->ResourcesTypes & (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT)) !=
1173 (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT))
1174 {
1175 DPRINT1("EHCI_StartController: Resources->ResourcesTypes - %x\n",
1176 Resources->ResourcesTypes);
1177
1178 return MP_STATUS_ERROR;
1179 }
1180
1181 CapabilityRegisters = (PEHCI_HC_CAPABILITY_REGISTERS)Resources->ResourceBase;
1182 EhciExtension->CapabilityRegisters = CapabilityRegisters;
1183
1184 CapabilityRegLength = READ_REGISTER_UCHAR(&CapabilityRegisters->RegistersLength);
1185
1186 OperationalRegs = (PEHCI_HW_REGISTERS)((ULONG_PTR)CapabilityRegisters +
1187 CapabilityRegLength);
1188
1189 EhciExtension->OperationalRegs = OperationalRegs;
1190
1191 DPRINT("EHCI_StartController: CapabilityRegisters - %p\n", CapabilityRegisters);
1192 DPRINT("EHCI_StartController: OperationalRegs - %p\n", OperationalRegs);
1193
1194 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1195 TRUE,
1196 &Fladj,
1197 EHCI_FLADJ_PCI_CONFIG_OFFSET,
1198 sizeof(Fladj));
1199
1200 EhciExtension->FrameLengthAdjustment = Fladj;
1201
1202 EHCI_GetRegistryParameters(EhciExtension);
1203
1204 MPStatus = EHCI_TakeControlHC(EhciExtension);
1205
1206 if (MPStatus)
1207 {
1208 DPRINT1("EHCI_StartController: Unsuccessful TakeControlHC()\n");
1209 return MPStatus;
1210 }
1211
1212 MPStatus = EHCI_InitializeHardware(EhciExtension);
1213
1214 if (MPStatus)
1215 {
1216 DPRINT1("EHCI_StartController: Unsuccessful InitializeHardware()\n");
1217 return MPStatus;
1218 }
1219
1220 MPStatus = EHCI_InitializeSchedule(EhciExtension,
1221 Resources->StartVA,
1222 Resources->StartPA);
1223
1224 if (MPStatus)
1225 {
1226 DPRINT1("EHCI_StartController: Unsuccessful InitializeSchedule()\n");
1227 return MPStatus;
1228 }
1229
1230 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1231 TRUE,
1232 &Fladj,
1233 EHCI_FLADJ_PCI_CONFIG_OFFSET,
1234 sizeof(Fladj));
1235
1236 if (Fladj != EhciExtension->FrameLengthAdjustment)
1237 {
1238 Fladj = EhciExtension->FrameLengthAdjustment;
1239
1240 RegPacket.UsbPortReadWriteConfigSpace(EhciExtension,
1241 FALSE, // write
1242 &Fladj,
1243 EHCI_FLADJ_PCI_CONFIG_OFFSET,
1244 sizeof(Fladj));
1245 }
1246
1247 /* Port routing control logic default-routes all ports to this HC */
1248 EhciExtension->PortRoutingControl = EHCI_CONFIG_FLAG_CONFIGURED;
1249 WRITE_REGISTER_ULONG(&OperationalRegs->ConfigFlag,
1250 EhciExtension->PortRoutingControl);
1251
1252 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1253 Command.InterruptThreshold = 1; // one micro-frame
1254 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1255
1256 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1257 Command.Run = 1; // execution of the schedule
1258 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1259
1260 EhciExtension->IsStarted = TRUE;
1261
1262 if (Resources->IsChirpHandled)
1263 {
1264 ULONG Port;
1265
1266 for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++)
1267 {
1268 EHCI_RH_SetFeaturePortPower(EhciExtension, Port);
1269 }
1270
1271 RegPacket.UsbPortWait(EhciExtension, 200);
1272
1273 for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++)
1274 {
1275 EHCI_RH_ChirpRootPort(EhciExtension, Port++);
1276 }
1277 }
1278
1279 return MPStatus;
1280 }
1281
1282 VOID
1283 NTAPI
1284 EHCI_StopController(IN PVOID ehciExtension,
1285 IN BOOLEAN DisableInterrupts)
1286 {
1287 DPRINT1("EHCI_StopController: UNIMPLEMENTED. FIXME\n");
1288 }
1289
1290 VOID
1291 NTAPI
1292 EHCI_SuspendController(IN PVOID ehciExtension)
1293 {
1294 PEHCI_EXTENSION EhciExtension = ehciExtension;
1295 PEHCI_HW_REGISTERS OperationalRegs;
1296 EHCI_USB_COMMAND Command;
1297 EHCI_USB_STATUS Status;
1298 EHCI_INTERRUPT_ENABLE IntrEn;
1299 ULONG ix;
1300
1301 DPRINT("EHCI_SuspendController: ... \n");
1302
1303 OperationalRegs = EhciExtension->OperationalRegs;
1304
1305 EhciExtension->BackupPeriodiclistbase = READ_REGISTER_ULONG(&OperationalRegs->PeriodicListBase);
1306 EhciExtension->BackupAsynclistaddr = READ_REGISTER_ULONG(&OperationalRegs->AsyncListBase);
1307 EhciExtension->BackupCtrlDSSegment = READ_REGISTER_ULONG(&OperationalRegs->SegmentSelector);
1308 EhciExtension->BackupUSBCmd = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1309
1310 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1311 Command.InterruptAdvanceDoorbell = 0;
1312 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1313
1314 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1315 Command.Run = 0;
1316 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1317
1318 KeStallExecutionProcessor(125);
1319
1320 Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1321
1322 Status.HCHalted = 0;
1323 Status.Reclamation = 0;
1324 Status.PeriodicStatus = 0;
1325 Status.AsynchronousStatus = 0;
1326
1327 if (Status.AsULONG)
1328 WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, Status.AsULONG);
1329
1330 WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, 0);
1331
1332 for (ix = 0; ix < 10; ix++)
1333 {
1334 Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1335
1336 if (Status.HCHalted)
1337 break;
1338
1339 RegPacket.UsbPortWait(EhciExtension, 1);
1340 }
1341
1342 if (!Status.HCHalted)
1343 DbgBreakPoint();
1344
1345 IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG);
1346 IntrEn.PortChangeInterrupt = 1;
1347 WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, IntrEn.AsULONG);
1348
1349 EhciExtension->Flags |= EHCI_FLAGS_CONTROLLER_SUSPEND;
1350 }
1351
1352 MPSTATUS
1353 NTAPI
1354 EHCI_ResumeController(IN PVOID ehciExtension)
1355 {
1356 PEHCI_EXTENSION EhciExtension = ehciExtension;
1357 PEHCI_HW_REGISTERS OperationalRegs;
1358 ULONG RoutingControl;
1359 EHCI_USB_COMMAND Command;
1360
1361 DPRINT("EHCI_ResumeController: ... \n");
1362
1363 OperationalRegs = EhciExtension->OperationalRegs;
1364
1365 RoutingControl = EhciExtension->PortRoutingControl;
1366
1367 if (!(RoutingControl & EHCI_CONFIG_FLAG_CONFIGURED))
1368 {
1369 EhciExtension->PortRoutingControl = RoutingControl | EHCI_CONFIG_FLAG_CONFIGURED;
1370 WRITE_REGISTER_ULONG(&OperationalRegs->ConfigFlag,
1371 EhciExtension->PortRoutingControl);
1372
1373 return MP_STATUS_HW_ERROR;
1374 }
1375
1376 WRITE_REGISTER_ULONG(&OperationalRegs->SegmentSelector,
1377 EhciExtension->BackupCtrlDSSegment);
1378
1379 WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase,
1380 EhciExtension->BackupPeriodiclistbase);
1381
1382 WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase,
1383 EhciExtension->BackupAsynclistaddr);
1384
1385 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1386
1387 Command.AsULONG = Command.AsULONG ^ EhciExtension->BackupUSBCmd;
1388
1389 Command.Reset = 0;
1390 Command.FrameListSize = 0;
1391 Command.InterruptAdvanceDoorbell = 0;
1392 Command.LightResetHC = 0;
1393 Command.AsynchronousParkModeCount = 0;
1394 Command.AsynchronousParkModeEnable = 0;
1395
1396 Command.Run = 1;
1397
1398 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG,
1399 Command.AsULONG);
1400
1401 WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG,
1402 EhciExtension->InterruptMask.AsULONG);
1403
1404 EhciExtension->Flags &= ~EHCI_FLAGS_CONTROLLER_SUSPEND;
1405
1406 return MP_STATUS_SUCCESS;
1407 }
1408
1409 BOOLEAN
1410 NTAPI
1411 EHCI_HardwarePresent(IN PEHCI_EXTENSION EhciExtension,
1412 IN BOOLEAN IsInvalidateController)
1413 {
1414 PEHCI_HW_REGISTERS OperationalRegs = EhciExtension->OperationalRegs;
1415
1416 if (READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG) != -1)
1417 return TRUE;
1418
1419 DPRINT1("EHCI_HardwarePresent: IsInvalidateController - %x\n",
1420 IsInvalidateController);
1421
1422 if (!IsInvalidateController)
1423 return FALSE;
1424
1425 RegPacket.UsbPortInvalidateController(EhciExtension,
1426 USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE);
1427 return FALSE;
1428 }
1429
1430 BOOLEAN
1431 NTAPI
1432 EHCI_InterruptService(IN PVOID ehciExtension)
1433 {
1434 PEHCI_EXTENSION EhciExtension = ehciExtension;
1435 PEHCI_HW_REGISTERS OperationalRegs;
1436 BOOLEAN Result = FALSE;
1437 EHCI_USB_STATUS IntrSts;
1438 EHCI_INTERRUPT_ENABLE IntrEn;
1439 EHCI_INTERRUPT_ENABLE iStatus;
1440 EHCI_USB_COMMAND Command;
1441 ULONG FrameIndex;
1442
1443 OperationalRegs = EhciExtension->OperationalRegs;
1444
1445 DPRINT_EHCI("EHCI_InterruptService: ... \n");
1446
1447 Result = EHCI_HardwarePresent(EhciExtension, FALSE);
1448
1449 if (!Result)
1450 return FALSE;
1451
1452 IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG);
1453 IntrSts.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1454
1455 iStatus.AsULONG = (IntrEn.AsULONG & IntrSts.AsULONG) & EHCI_INTERRUPT_MASK;
1456
1457 if (!iStatus.AsULONG)
1458 return FALSE;
1459
1460 EhciExtension->InterruptStatus = iStatus;
1461
1462 WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, iStatus.AsULONG);
1463
1464 if (iStatus.HostSystemError)
1465 {
1466 EhciExtension->HcSystemErrors++;
1467
1468 if (EhciExtension->HcSystemErrors < EHCI_MAX_HC_SYSTEM_ERRORS)
1469 {
1470 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1471 Command.Run = 1;
1472 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1473 }
1474 }
1475
1476 FrameIndex = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) / EHCI_MICROFRAMES;
1477 FrameIndex &= EHCI_FRINDEX_FRAME_MASK;
1478
1479 if ((FrameIndex ^ EhciExtension->FrameIndex) & EHCI_FRAME_LIST_MAX_ENTRIES)
1480 {
1481 EhciExtension->FrameHighPart += 2 * EHCI_FRAME_LIST_MAX_ENTRIES;
1482
1483 EhciExtension->FrameHighPart -= (FrameIndex ^ EhciExtension->FrameHighPart) &
1484 EHCI_FRAME_LIST_MAX_ENTRIES;
1485 }
1486
1487 EhciExtension->FrameIndex = FrameIndex;
1488
1489 return TRUE;
1490 }
1491
1492 VOID
1493 NTAPI
1494 EHCI_InterruptDpc(IN PVOID ehciExtension,
1495 IN BOOLEAN EnableInterrupts)
1496 {
1497 PEHCI_EXTENSION EhciExtension = ehciExtension;
1498 PEHCI_HW_REGISTERS OperationalRegs;
1499 EHCI_INTERRUPT_ENABLE iStatus;
1500
1501 OperationalRegs = EhciExtension->OperationalRegs;
1502
1503 DPRINT_EHCI("EHCI_InterruptDpc: [%p] EnableInterrupts - %x\n",
1504 EhciExtension, EnableInterrupts);
1505
1506 iStatus = EhciExtension->InterruptStatus;
1507 EhciExtension->InterruptStatus.AsULONG = 0;
1508
1509 if (iStatus.Interrupt == 1 ||
1510 iStatus.ErrorInterrupt == 1 ||
1511 iStatus.InterruptOnAsyncAdvance == 1)
1512 {
1513 DPRINT_EHCI("EHCI_InterruptDpc: [%p] InterruptStatus - %X\n", EhciExtension, iStatus.AsULONG);
1514 RegPacket.UsbPortInvalidateEndpoint(EhciExtension, NULL);
1515 }
1516
1517 if (iStatus.PortChangeInterrupt == 1)
1518 {
1519 DPRINT_EHCI("EHCI_InterruptDpc: [%p] PortChangeInterrupt\n", EhciExtension);
1520 RegPacket.UsbPortInvalidateRootHub(EhciExtension);
1521 }
1522
1523 if (EnableInterrupts)
1524 {
1525 WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG,
1526 EhciExtension->InterruptMask.AsULONG);
1527 }
1528 }
1529
1530 ULONG
1531 NTAPI
1532 EHCI_MapAsyncTransferToTd(IN PEHCI_EXTENSION EhciExtension,
1533 IN ULONG MaxPacketSize,
1534 IN ULONG TransferedLen,
1535 IN PULONG DataToggle,
1536 IN PEHCI_TRANSFER EhciTransfer,
1537 IN PEHCI_HCD_TD TD,
1538 IN PUSBPORT_SCATTER_GATHER_LIST SgList)
1539 {
1540 PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
1541 PUSBPORT_SCATTER_GATHER_ELEMENT SgElement;
1542 ULONG SgIdx;
1543 ULONG LengthThisTD;
1544 ULONG ix;
1545 ULONG SgRemain;
1546 ULONG DiffLength;
1547 ULONG NumPackets;
1548
1549 DPRINT_EHCI("EHCI_MapAsyncTransferToTd: EhciTransfer - %p, TD - %p, TransferedLen - %x, MaxPacketSize - %x, DataToggle - %x\n",
1550 EhciTransfer,
1551 TD,
1552 TransferedLen,
1553 MaxPacketSize,
1554 DataToggle);
1555
1556 TransferParameters = EhciTransfer->TransferParameters;
1557
1558 SgElement = &SgList->SgElement[0];
1559
1560 for (SgIdx = 0; SgIdx < SgList->SgElementCount; SgIdx++)
1561 {
1562 if (TransferedLen >= SgElement->SgOffset &&
1563 TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength)
1564 {
1565 break;
1566 }
1567
1568 SgElement += 1;
1569 }
1570
1571 SgRemain = SgList->SgElementCount - SgIdx;
1572
1573 if (SgRemain > EHCI_MAX_QTD_BUFFER_PAGES)
1574 {
1575 TD->HwTD.Buffer[0] = SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart -
1576 SgList->SgElement[SgIdx].SgOffset +
1577 TransferedLen;
1578
1579 LengthThisTD = EHCI_MAX_QTD_BUFFER_PAGES * PAGE_SIZE -
1580 (TD->HwTD.Buffer[0] & (PAGE_SIZE - 1));
1581
1582 for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; ix++)
1583 {
1584 TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart;
1585 }
1586
1587 NumPackets = LengthThisTD / MaxPacketSize;
1588 DiffLength = LengthThisTD - MaxPacketSize * (LengthThisTD / MaxPacketSize);
1589
1590 if (LengthThisTD != MaxPacketSize * (LengthThisTD / MaxPacketSize))
1591 LengthThisTD -= DiffLength;
1592
1593 if (DataToggle && (NumPackets & 1))
1594 *DataToggle = !(*DataToggle);
1595 }
1596 else
1597 {
1598 LengthThisTD = TransferParameters->TransferBufferLength - TransferedLen;
1599
1600 TD->HwTD.Buffer[0] = TransferedLen +
1601 SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart -
1602 SgList->SgElement[SgIdx].SgOffset;
1603
1604 for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; ix++)
1605 {
1606 if ((SgIdx + ix) >= SgList->SgElementCount)
1607 break;
1608
1609 TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart;
1610 }
1611 }
1612
1613 TD->HwTD.Token.TransferBytes = LengthThisTD;
1614 TD->LengthThisTD = LengthThisTD;
1615
1616 return LengthThisTD + TransferedLen;
1617 }
1618
1619 VOID
1620 NTAPI
1621 EHCI_EnableAsyncList(IN PEHCI_EXTENSION EhciExtension)
1622 {
1623 PEHCI_HW_REGISTERS OperationalRegs;
1624 EHCI_USB_COMMAND UsbCmd;
1625
1626 DPRINT_EHCI("EHCI_EnableAsyncList: ... \n");
1627
1628 OperationalRegs = EhciExtension->OperationalRegs;
1629
1630 UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1631 UsbCmd.AsynchronousEnable = 1;
1632 WRITE_REGISTER_ULONG((&OperationalRegs->HcCommand.AsULONG), UsbCmd.AsULONG);
1633 }
1634
1635 VOID
1636 NTAPI
1637 EHCI_DisableAsyncList(IN PEHCI_EXTENSION EhciExtension)
1638 {
1639 PEHCI_HW_REGISTERS OperationalRegs;
1640 EHCI_USB_COMMAND UsbCmd;
1641
1642 DPRINT("EHCI_DisableAsyncList: ... \n");
1643
1644 OperationalRegs = EhciExtension->OperationalRegs;
1645
1646 UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1647 UsbCmd.AsynchronousEnable = 0;
1648 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, UsbCmd.AsULONG);
1649 }
1650
1651 VOID
1652 NTAPI
1653 EHCI_EnablePeriodicList(IN PEHCI_EXTENSION EhciExtension)
1654 {
1655 PEHCI_HW_REGISTERS OperationalRegs;
1656 EHCI_USB_COMMAND Command;
1657
1658 DPRINT("EHCI_EnablePeriodicList: ... \n");
1659
1660 OperationalRegs = EhciExtension->OperationalRegs;
1661
1662 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1663 Command.PeriodicEnable = 1;
1664 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1665 }
1666
1667 VOID
1668 NTAPI
1669 EHCI_FlushAsyncCache(IN PEHCI_EXTENSION EhciExtension)
1670 {
1671 PEHCI_HW_REGISTERS OperationalRegs;
1672 EHCI_USB_COMMAND Command;
1673 EHCI_USB_STATUS Status;
1674 LARGE_INTEGER CurrentTime;
1675 LARGE_INTEGER EndTime;
1676 EHCI_USB_COMMAND Cmd;
1677
1678 DPRINT_EHCI("EHCI_FlushAsyncCache: EhciExtension - %p\n", EhciExtension);
1679
1680 OperationalRegs = EhciExtension->OperationalRegs;
1681 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1682 Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1683
1684 if (!Status.AsynchronousStatus && !Command.AsynchronousEnable)
1685 return;
1686
1687 if (Status.AsynchronousStatus && !Command.AsynchronousEnable)
1688 {
1689 KeQuerySystemTime(&EndTime);
1690 EndTime.QuadPart += 100 * 10000; //100 ms
1691
1692 do
1693 {
1694 Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1695 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1696 KeQuerySystemTime(&CurrentTime);
1697
1698 if (CurrentTime.QuadPart > EndTime.QuadPart)
1699 RegPacket.UsbPortBugCheck(EhciExtension);
1700 }
1701 while (Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run);
1702
1703 return;
1704 }
1705
1706 if (!Status.AsynchronousStatus && Command.AsynchronousEnable)
1707 {
1708 KeQuerySystemTime(&EndTime);
1709 EndTime.QuadPart += 100 * 10000; //100 ms
1710
1711 do
1712 {
1713 Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG);
1714 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1715 KeQuerySystemTime(&CurrentTime);
1716 }
1717 while (!Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run);
1718 }
1719
1720 Command.InterruptAdvanceDoorbell = 1;
1721 WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG);
1722
1723 KeQuerySystemTime(&EndTime);
1724 EndTime.QuadPart += 100 * 10000; //100 ms
1725
1726 Cmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1727
1728 if (Cmd.InterruptAdvanceDoorbell)
1729 {
1730 while (Cmd.Run)
1731 {
1732 if (Cmd.AsULONG == -1)
1733 break;
1734
1735 KeStallExecutionProcessor(1);
1736 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1737 KeQuerySystemTime(&CurrentTime);
1738
1739 if (!Command.InterruptAdvanceDoorbell)
1740 break;
1741
1742 Cmd = Command;
1743 }
1744 }
1745
1746 /* InterruptOnAsyncAdvance */
1747 WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, 0x20);
1748 }
1749
1750 VOID
1751 NTAPI
1752 EHCI_LockQH(IN PEHCI_EXTENSION EhciExtension,
1753 IN PEHCI_HCD_QH QH,
1754 IN ULONG TransferType)
1755 {
1756 PEHCI_HCD_QH PrevQH;
1757 PEHCI_HCD_QH NextQH;
1758 ULONG QhPA;
1759 ULONG FrameIndexReg;
1760 PEHCI_HW_REGISTERS OperationalRegs;
1761 EHCI_USB_COMMAND Command;
1762
1763 DPRINT_EHCI("EHCI_LockQH: QH - %p, TransferType - %x\n",
1764 QH,
1765 TransferType);
1766
1767 OperationalRegs = EhciExtension->OperationalRegs;
1768
1769 ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING) == 0);
1770 ASSERT(EhciExtension->LockQH == NULL);
1771
1772 PrevQH = QH->sqh.PrevHead;
1773 QH->sqh.QhFlags |= EHCI_QH_FLAG_UPDATING;
1774
1775 ASSERT(PrevQH);
1776
1777 NextQH = QH->sqh.NextHead;
1778
1779 EhciExtension->PrevQH = PrevQH;
1780 EhciExtension->NextQH = NextQH;
1781 EhciExtension->LockQH = QH;
1782
1783 if (NextQH)
1784 {
1785 QhPA = NextQH->sqh.PhysicalAddress;
1786 QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
1787 QhPA |= (EHCI_LINK_TYPE_QH << 1);
1788 }
1789 else
1790 {
1791 QhPA = TERMINATE_POINTER;
1792 }
1793
1794 PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
1795
1796 FrameIndexReg = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex);
1797
1798 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1799 {
1800 do
1801 {
1802 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
1803 }
1804 while (READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) ==
1805 FrameIndexReg && (Command.AsULONG != -1) && Command.Run);
1806 }
1807 else
1808 {
1809 EHCI_FlushAsyncCache(EhciExtension);
1810 }
1811 }
1812
1813 VOID
1814 NTAPI
1815 EHCI_UnlockQH(IN PEHCI_EXTENSION EhciExtension,
1816 IN PEHCI_HCD_QH QH)
1817 {
1818 ULONG QhPA;
1819
1820 DPRINT_EHCI("EHCI_UnlockQH: QH - %p\n", QH);
1821
1822 ASSERT(QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING);
1823 ASSERT(EhciExtension->LockQH);
1824 ASSERT(EhciExtension->LockQH == QH);
1825
1826 QH->sqh.QhFlags &= ~EHCI_QH_FLAG_UPDATING;
1827
1828 EhciExtension->LockQH = NULL;
1829
1830 QhPA = QH->sqh.PhysicalAddress;
1831 QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
1832 QhPA |= (EHCI_LINK_TYPE_QH << 1);
1833
1834 EhciExtension->PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
1835 }
1836
1837 VOID
1838 NTAPI
1839 EHCI_LinkTransferToQueue(IN PEHCI_EXTENSION EhciExtension,
1840 IN PEHCI_ENDPOINT EhciEndpoint,
1841 IN PEHCI_HCD_TD NextTD)
1842 {
1843 PEHCI_HCD_QH QH;
1844 PEHCI_HCD_TD TD;
1845 PEHCI_TRANSFER Transfer;
1846 PEHCI_HCD_TD LinkTD;
1847 BOOLEAN IsPresent;
1848 ULONG ix;
1849
1850 DPRINT_EHCI("EHCI_LinkTransferToQueue: EhciEndpoint - %p, NextTD - %p\n",
1851 EhciEndpoint,
1852 NextTD);
1853
1854 ASSERT(EhciEndpoint->HcdHeadP != NULL);
1855 IsPresent = EHCI_HardwarePresent(EhciExtension, 0);
1856
1857 QH = EhciEndpoint->QH;
1858 TD = EhciEndpoint->HcdHeadP;
1859
1860 if (TD == EhciEndpoint->HcdTailP)
1861 {
1862 if (IsPresent)
1863 {
1864 EHCI_LockQH(EhciExtension,
1865 QH,
1866 EhciEndpoint->EndpointProperties.TransferType);
1867 }
1868
1869 QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
1870 QH->sqh.HwQH.NextTD = NextTD->PhysicalAddress;
1871 QH->sqh.HwQH.AlternateNextTD = NextTD->HwTD.AlternateNextTD;
1872
1873 QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
1874 EHCI_TOKEN_STATUS_HALTED);
1875
1876 QH->sqh.HwQH.Token.TransferBytes = 0;
1877
1878 if (IsPresent)
1879 EHCI_UnlockQH(EhciExtension, QH);
1880
1881 EhciEndpoint->HcdHeadP = NextTD;
1882 }
1883 else
1884 {
1885 DPRINT_EHCI("EHCI_LinkTransferToQueue: TD - %p, HcdTailP - %p\n",
1886 EhciEndpoint->HcdHeadP,
1887 EhciEndpoint->HcdTailP);
1888
1889 LinkTD = EhciEndpoint->HcdHeadP;
1890
1891 while (TD != EhciEndpoint->HcdTailP)
1892 {
1893 LinkTD = TD;
1894 TD = TD->NextHcdTD;
1895 }
1896
1897 ASSERT(LinkTD != EhciEndpoint->HcdTailP);
1898
1899 Transfer = LinkTD->EhciTransfer;
1900
1901 TD = EhciEndpoint->FirstTD;
1902
1903 for (ix = 0; ix < EhciEndpoint->MaxTDs; ix++)
1904 {
1905 if (TD->EhciTransfer == Transfer)
1906 {
1907 TD->AltNextHcdTD = NextTD;
1908 TD->HwTD.AlternateNextTD = NextTD->PhysicalAddress;
1909 }
1910
1911 TD += 1;
1912 }
1913
1914 LinkTD->HwTD.NextTD = NextTD->PhysicalAddress;
1915 LinkTD->NextHcdTD = NextTD;
1916
1917 if (QH->sqh.HwQH.CurrentTD == LinkTD->PhysicalAddress)
1918 {
1919 QH->sqh.HwQH.NextTD = NextTD->PhysicalAddress;
1920 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
1921 }
1922 }
1923 }
1924
1925 MPSTATUS
1926 NTAPI
1927 EHCI_ControlTransfer(IN PEHCI_EXTENSION EhciExtension,
1928 IN PEHCI_ENDPOINT EhciEndpoint,
1929 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
1930 IN PEHCI_TRANSFER EhciTransfer,
1931 IN PUSBPORT_SCATTER_GATHER_LIST SgList)
1932 {
1933 PEHCI_HCD_TD FirstTD;
1934 PEHCI_HCD_TD LastTD;
1935 PEHCI_HCD_TD TD;
1936 PEHCI_HCD_TD PrevTD;
1937 PEHCI_HCD_TD LinkTD;
1938 ULONG TransferedLen = 0;
1939 EHCI_TD_TOKEN Token;
1940 ULONG DataToggle = 1;
1941
1942 DPRINT_EHCI("EHCI_ControlTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
1943 EhciEndpoint,
1944 EhciTransfer);
1945
1946 if (EhciEndpoint->RemainTDs < EHCI_MAX_CONTROL_TD_COUNT)
1947 return MP_STATUS_FAILURE;
1948
1949 EhciExtension->PendingTransfers++;
1950 EhciEndpoint->PendingTDs++;
1951
1952 EhciTransfer->TransferOnAsyncList = 1;
1953
1954 FirstTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
1955
1956 if (!FirstTD)
1957 {
1958 RegPacket.UsbPortBugCheck(EhciExtension);
1959 return MP_STATUS_FAILURE;
1960 }
1961
1962 EhciTransfer->PendingTDs++;
1963
1964 FirstTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
1965 FirstTD->EhciTransfer = EhciTransfer;
1966
1967 FirstTD->HwTD.Buffer[0] = FirstTD->PhysicalAddress + FIELD_OFFSET(EHCI_HCD_TD, SetupPacket);
1968 FirstTD->HwTD.Buffer[1] = 0;
1969 FirstTD->HwTD.Buffer[2] = 0;
1970 FirstTD->HwTD.Buffer[3] = 0;
1971 FirstTD->HwTD.Buffer[4] = 0;
1972
1973 FirstTD->NextHcdTD = NULL;
1974
1975 FirstTD->HwTD.NextTD = TERMINATE_POINTER;
1976 FirstTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
1977
1978 FirstTD->HwTD.Token.AsULONG = 0;
1979 FirstTD->HwTD.Token.ErrorCounter = 3;
1980 FirstTD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_SETUP;
1981 FirstTD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
1982 FirstTD->HwTD.Token.TransferBytes = sizeof(FirstTD->SetupPacket);
1983
1984 RtlCopyMemory(&FirstTD->SetupPacket,
1985 &TransferParameters->SetupPacket,
1986 sizeof(FirstTD->SetupPacket));
1987
1988 LastTD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
1989
1990 if (!LastTD)
1991 {
1992 RegPacket.UsbPortBugCheck(EhciExtension);
1993 return MP_STATUS_FAILURE;
1994 }
1995
1996 EhciTransfer->PendingTDs++;
1997
1998 LastTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
1999 LastTD->EhciTransfer = EhciTransfer;
2000
2001 LastTD->HwTD.Buffer[0] = 0;
2002 LastTD->HwTD.Buffer[1] = 0;
2003 LastTD->HwTD.Buffer[2] = 0;
2004 LastTD->HwTD.Buffer[3] = 0;
2005 LastTD->HwTD.Buffer[4] = 0;
2006
2007 LastTD->NextHcdTD = NULL;
2008 LastTD->HwTD.NextTD = TERMINATE_POINTER;
2009 LastTD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2010
2011 LastTD->HwTD.Token.AsULONG = 0;
2012 LastTD->HwTD.Token.ErrorCounter = 3;
2013
2014 FirstTD->AltNextHcdTD = LastTD;
2015 FirstTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2016
2017 PrevTD = FirstTD;
2018 LinkTD = FirstTD;
2019
2020 while (TransferedLen < TransferParameters->TransferBufferLength)
2021 {
2022 TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2023
2024 if (!TD)
2025 {
2026 RegPacket.UsbPortBugCheck(EhciExtension);
2027 return MP_STATUS_FAILURE;
2028 }
2029
2030 LinkTD = TD;
2031
2032 EhciTransfer->PendingTDs++;
2033
2034 TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2035 TD->EhciTransfer = EhciTransfer;
2036
2037 TD->HwTD.Buffer[0] = 0;
2038 TD->HwTD.Buffer[1] = 0;
2039 TD->HwTD.Buffer[2] = 0;
2040 TD->HwTD.Buffer[3] = 0;
2041 TD->HwTD.Buffer[4] = 0;
2042
2043 TD->NextHcdTD = NULL;
2044
2045 TD->HwTD.NextTD = TERMINATE_POINTER;
2046 TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2047
2048 TD->HwTD.Token.AsULONG = 0;
2049 TD->HwTD.Token.ErrorCounter = 3;
2050
2051 PrevTD->NextHcdTD = TD;
2052 PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2053
2054 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2055 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2056 else
2057 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2058
2059 TD->HwTD.Token.DataToggle = DataToggle;
2060 TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2061
2062 if (DataToggle)
2063 TD->HwTD.Token.DataToggle = 1;
2064 else
2065 TD->HwTD.Token.DataToggle = 0;
2066
2067 TD->AltNextHcdTD = LastTD;
2068 TD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2069
2070 TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2071 EhciEndpoint->EndpointProperties.MaxPacketSize,
2072 TransferedLen,
2073 &DataToggle,
2074 EhciTransfer,
2075 TD,
2076 SgList);
2077
2078 PrevTD = TD;
2079 }
2080
2081 LinkTD->NextHcdTD = LastTD;
2082 LinkTD->HwTD.NextTD = LastTD->PhysicalAddress;
2083
2084 LastTD->HwTD.Buffer[0] = 0;
2085 LastTD->LengthThisTD = 0;
2086
2087 Token.AsULONG = 0;
2088 Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2089 Token.InterruptOnComplete = 1;
2090 Token.DataToggle = 1;
2091
2092 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2093 Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2094 else
2095 Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2096
2097 LastTD->HwTD.Token = Token;
2098
2099 LastTD->NextHcdTD = EhciEndpoint->HcdTailP;
2100 LastTD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2101
2102 EHCI_EnableAsyncList(EhciExtension);
2103 EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2104
2105 ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL);
2106 ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL);
2107
2108 return MP_STATUS_SUCCESS;
2109 }
2110
2111 MPSTATUS
2112 NTAPI
2113 EHCI_BulkTransfer(IN PEHCI_EXTENSION EhciExtension,
2114 IN PEHCI_ENDPOINT EhciEndpoint,
2115 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2116 IN PEHCI_TRANSFER EhciTransfer,
2117 IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2118 {
2119 PEHCI_HCD_TD PrevTD;
2120 PEHCI_HCD_TD FirstTD;
2121 PEHCI_HCD_TD TD;
2122 ULONG TransferedLen;
2123
2124 DPRINT_EHCI("EHCI_BulkTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2125 EhciEndpoint,
2126 EhciTransfer);
2127
2128 if (((TransferParameters->TransferBufferLength /
2129 ((EHCI_MAX_QTD_BUFFER_PAGES - 1) * PAGE_SIZE)) + 1) > EhciEndpoint->RemainTDs)
2130 {
2131 DPRINT1("EHCI_BulkTransfer: return MP_STATUS_FAILURE\n");
2132 return MP_STATUS_FAILURE;
2133 }
2134
2135 EhciExtension->PendingTransfers++;
2136 EhciEndpoint->PendingTDs++;
2137
2138 EhciTransfer->TransferOnAsyncList = 1;
2139
2140 TransferedLen = 0;
2141 PrevTD = NULL;
2142
2143 if (TransferParameters->TransferBufferLength)
2144 {
2145 while (TransferedLen < TransferParameters->TransferBufferLength)
2146 {
2147 TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2148
2149 if (!TD)
2150 {
2151 RegPacket.UsbPortBugCheck(EhciExtension);
2152 return MP_STATUS_FAILURE;
2153 }
2154
2155 EhciTransfer->PendingTDs++;
2156
2157 TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2158 TD->EhciTransfer = EhciTransfer;
2159
2160 TD->HwTD.Buffer[0] = 0;
2161 TD->HwTD.Buffer[1] = 0;
2162 TD->HwTD.Buffer[2] = 0;
2163 TD->HwTD.Buffer[3] = 0;
2164 TD->HwTD.Buffer[4] = 0;
2165
2166 TD->NextHcdTD = NULL;
2167 TD->HwTD.NextTD = TERMINATE_POINTER;
2168 TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2169
2170 TD->HwTD.Token.AsULONG = 0;
2171 TD->HwTD.Token.ErrorCounter = 3;
2172
2173 if (EhciTransfer->PendingTDs == 1)
2174 {
2175 FirstTD = TD;
2176 }
2177 else
2178 {
2179 PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2180 PrevTD->NextHcdTD = TD;
2181 }
2182
2183 TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2184 TD->AltNextHcdTD = EhciEndpoint->HcdTailP;
2185
2186 TD->HwTD.Token.InterruptOnComplete = 1;
2187
2188 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2189 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2190 else
2191 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2192
2193 TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2194 TD->HwTD.Token.DataToggle = 1;
2195
2196 TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2197 EhciEndpoint->EndpointProperties.MaxPacketSize,
2198 TransferedLen,
2199 0,
2200 EhciTransfer,
2201 TD,
2202 SgList);
2203
2204 PrevTD = TD;
2205 }
2206 }
2207 else
2208 {
2209 TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2210
2211 if (!TD)
2212 {
2213 RegPacket.UsbPortBugCheck(EhciExtension);
2214 return MP_STATUS_FAILURE;
2215 }
2216
2217 EhciTransfer->PendingTDs++;
2218
2219 TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2220 TD->EhciTransfer = EhciTransfer;
2221
2222 TD->HwTD.Buffer[0] = 0;
2223 TD->HwTD.Buffer[1] = 0;
2224 TD->HwTD.Buffer[2] = 0;
2225 TD->HwTD.Buffer[3] = 0;
2226 TD->HwTD.Buffer[4] = 0;
2227
2228 TD->HwTD.NextTD = TERMINATE_POINTER;
2229 TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2230
2231 TD->HwTD.Token.AsULONG = 0;
2232 TD->HwTD.Token.ErrorCounter = 3;
2233
2234 TD->NextHcdTD = NULL;
2235
2236 ASSERT(EhciTransfer->PendingTDs == 1);
2237
2238 FirstTD = TD;
2239
2240 TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2241 TD->AltNextHcdTD = EhciEndpoint->HcdTailP;
2242
2243 TD->HwTD.Token.InterruptOnComplete = 1;
2244
2245 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2246 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2247 else
2248 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2249
2250 TD->HwTD.Buffer[0] = TD->PhysicalAddress;
2251
2252 TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2253 TD->HwTD.Token.DataToggle = 1;
2254
2255 TD->LengthThisTD = 0;
2256 }
2257
2258 TD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2259 TD->NextHcdTD = EhciEndpoint->HcdTailP;
2260
2261 EHCI_EnableAsyncList(EhciExtension);
2262 EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2263
2264 ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == 0);
2265 ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == 0);
2266
2267 return MP_STATUS_SUCCESS;
2268 }
2269
2270 MPSTATUS
2271 NTAPI
2272 EHCI_InterruptTransfer(IN PEHCI_EXTENSION EhciExtension,
2273 IN PEHCI_ENDPOINT EhciEndpoint,
2274 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2275 IN PEHCI_TRANSFER EhciTransfer,
2276 IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2277 {
2278 PEHCI_HCD_TD TD;
2279 PEHCI_HCD_TD FirstTD;
2280 PEHCI_HCD_TD PrevTD = NULL;
2281 ULONG TransferedLen = 0;
2282
2283 DPRINT_EHCI("EHCI_InterruptTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2284 EhciEndpoint,
2285 EhciTransfer);
2286
2287 if (!EhciEndpoint->RemainTDs)
2288 {
2289 DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2290 DbgBreakPoint();
2291 return MP_STATUS_FAILURE;
2292 }
2293
2294 EhciEndpoint->PendingTDs++;
2295
2296 if (!TransferParameters->TransferBufferLength)
2297 {
2298 DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2299 DbgBreakPoint();
2300 return MP_STATUS_FAILURE;
2301 }
2302
2303 while (TransferedLen < TransferParameters->TransferBufferLength)
2304 {
2305 TD = EHCI_AllocTd(EhciExtension, EhciEndpoint);
2306
2307 if (!TD)
2308 {
2309 DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint);
2310 RegPacket.UsbPortBugCheck(EhciExtension);
2311 return MP_STATUS_FAILURE;
2312 }
2313
2314 EhciTransfer->PendingTDs++;
2315
2316 TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED;
2317 TD->EhciTransfer = EhciTransfer;
2318
2319 TD->HwTD.Buffer[0] = 0;
2320 TD->HwTD.Buffer[1] = 0;
2321 TD->HwTD.Buffer[2] = 0;
2322 TD->HwTD.Buffer[3] = 0;
2323 TD->HwTD.Buffer[4] = 0;
2324
2325 TD->HwTD.NextTD = TERMINATE_POINTER;
2326 TD->HwTD.AlternateNextTD = TERMINATE_POINTER;
2327
2328 TD->HwTD.Token.AsULONG = 0;
2329 TD->HwTD.Token.ErrorCounter = 3;
2330
2331 TD->NextHcdTD = NULL;
2332
2333 if (EhciTransfer->PendingTDs == 1)
2334 {
2335 FirstTD = TD;
2336 }
2337 else if (PrevTD)
2338 {
2339 PrevTD->HwTD.NextTD = TD->PhysicalAddress;
2340 PrevTD->NextHcdTD = TD;
2341 }
2342
2343 if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
2344 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN;
2345 else
2346 TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT;
2347
2348 TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE;
2349 TD->HwTD.Token.DataToggle = 1;
2350
2351 TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension,
2352 EhciEndpoint->EndpointProperties.TotalMaxPacketSize,
2353 TransferedLen,
2354 NULL,
2355 EhciTransfer,
2356 TD,
2357 SgList);
2358
2359 PrevTD = TD;
2360 }
2361
2362 TD->HwTD.Token.InterruptOnComplete = 1;
2363
2364 DPRINT_EHCI("EHCI_InterruptTransfer: PendingTDs - %x, TD->PhysicalAddress - %p, FirstTD - %p\n",
2365 EhciTransfer->PendingTDs,
2366 TD->PhysicalAddress,
2367 FirstTD);
2368
2369 TD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress;
2370 TD->NextHcdTD = EhciEndpoint->HcdTailP;
2371
2372 EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD);
2373
2374 ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL);
2375 ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL);
2376
2377 EHCI_EnablePeriodicList(EhciExtension);
2378
2379 return MP_STATUS_SUCCESS;
2380 }
2381
2382 MPSTATUS
2383 NTAPI
2384 EHCI_SubmitTransfer(IN PVOID ehciExtension,
2385 IN PVOID ehciEndpoint,
2386 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2387 IN PVOID ehciTransfer,
2388 IN PUSBPORT_SCATTER_GATHER_LIST SgList)
2389 {
2390 PEHCI_EXTENSION EhciExtension = ehciExtension;
2391 PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
2392 PEHCI_TRANSFER EhciTransfer = ehciTransfer;
2393 MPSTATUS MPStatus;
2394
2395 DPRINT_EHCI("EHCI_SubmitTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2396 EhciEndpoint,
2397 EhciTransfer);
2398
2399 RtlZeroMemory(EhciTransfer, sizeof(EHCI_TRANSFER));
2400
2401 EhciTransfer->TransferParameters = TransferParameters;
2402 EhciTransfer->USBDStatus = USBD_STATUS_SUCCESS;
2403 EhciTransfer->EhciEndpoint = EhciEndpoint;
2404
2405 switch (EhciEndpoint->EndpointProperties.TransferType)
2406 {
2407 case USBPORT_TRANSFER_TYPE_CONTROL:
2408 MPStatus = EHCI_ControlTransfer(EhciExtension,
2409 EhciEndpoint,
2410 TransferParameters,
2411 EhciTransfer,
2412 SgList);
2413 break;
2414
2415 case USBPORT_TRANSFER_TYPE_BULK:
2416 MPStatus = EHCI_BulkTransfer(EhciExtension,
2417 EhciEndpoint,
2418 TransferParameters,
2419 EhciTransfer,
2420 SgList);
2421 break;
2422
2423 case USBPORT_TRANSFER_TYPE_INTERRUPT:
2424 MPStatus = EHCI_InterruptTransfer(EhciExtension,
2425 EhciEndpoint,
2426 TransferParameters,
2427 EhciTransfer,
2428 SgList);
2429 break;
2430
2431 default:
2432 DbgBreakPoint();
2433 MPStatus = MP_STATUS_NOT_SUPPORTED;
2434 break;
2435 }
2436
2437 return MPStatus;
2438 }
2439
2440 MPSTATUS
2441 NTAPI
2442 EHCI_SubmitIsoTransfer(IN PVOID ehciExtension,
2443 IN PVOID ehciEndpoint,
2444 IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters,
2445 IN PVOID ehciTransfer,
2446 IN PVOID isoParameters)
2447 {
2448 DPRINT1("EHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n");
2449 return MP_STATUS_SUCCESS;
2450 }
2451
2452 VOID
2453 NTAPI
2454 EHCI_AbortIsoTransfer(IN PEHCI_EXTENSION EhciExtension,
2455 IN PEHCI_ENDPOINT EhciEndpoint,
2456 IN PEHCI_TRANSFER EhciTransfer)
2457 {
2458 DPRINT1("EHCI_AbortIsoTransfer: UNIMPLEMENTED. FIXME\n");
2459 }
2460
2461 VOID
2462 NTAPI
2463 EHCI_AbortAsyncTransfer(IN PEHCI_EXTENSION EhciExtension,
2464 IN PEHCI_ENDPOINT EhciEndpoint,
2465 IN PEHCI_TRANSFER EhciTransfer)
2466 {
2467 PEHCI_HCD_QH QH;
2468 PEHCI_HCD_TD TD;
2469 ULONG TransferLength;
2470 PEHCI_HCD_TD CurrentTD;
2471 PEHCI_TRANSFER CurrentTransfer;
2472 ULONG FirstTdPA;
2473 PEHCI_HCD_TD LastTD;
2474 PEHCI_HCD_TD PrevTD;
2475 ULONG NextTD;
2476
2477 DPRINT("EHCI_AbortAsyncTransfer: EhciEndpoint - %p, EhciTransfer - %p\n",
2478 EhciEndpoint,
2479 EhciTransfer);
2480
2481 QH = EhciEndpoint->QH;
2482 TD = EhciEndpoint->HcdHeadP;
2483
2484 ASSERT(EhciEndpoint->PendingTDs);
2485 EhciEndpoint->PendingTDs--;
2486
2487 if (TD->EhciTransfer == EhciTransfer)
2488 {
2489 TransferLength = 0;
2490
2491 while (TD != EhciEndpoint->HcdTailP &&
2492 TD->EhciTransfer == EhciTransfer)
2493 {
2494 TransferLength += TD->LengthThisTD - TD->HwTD.Token.TransferBytes;
2495
2496 TD->HwTD.NextTD = 0;
2497 TD->HwTD.AlternateNextTD = 0;
2498
2499 TD->TdFlags = 0;
2500 TD->EhciTransfer = NULL;
2501
2502 EhciEndpoint->RemainTDs++;
2503
2504 TD = TD->NextHcdTD;
2505 }
2506
2507 if (TransferLength)
2508 EhciTransfer->TransferLen += TransferLength;
2509
2510 QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
2511 QH->sqh.HwQH.NextTD = TD->PhysicalAddress;
2512 QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD;
2513
2514 QH->sqh.HwQH.Token.TransferBytes = 0;
2515 QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
2516 EHCI_TOKEN_STATUS_HALTED);
2517
2518 EhciEndpoint->HcdHeadP = TD;
2519 }
2520 else
2521 {
2522 DPRINT("EHCI_AbortAsyncTransfer: TD->EhciTransfer - %p\n", TD->EhciTransfer);
2523
2524 CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(QH->sqh.HwQH.CurrentTD,
2525 EhciExtension,
2526 EhciEndpoint);
2527
2528 CurrentTransfer = CurrentTD->EhciTransfer;
2529 TD = EhciEndpoint->HcdHeadP;
2530
2531 while (TD && TD->EhciTransfer != EhciTransfer)
2532 {
2533 PrevTD = TD;
2534 TD = TD->NextHcdTD;
2535 }
2536
2537 FirstTdPA = TD->PhysicalAddress;
2538
2539 while (TD && TD->EhciTransfer == EhciTransfer)
2540 {
2541 TD->HwTD.NextTD = 0;
2542 TD->HwTD.AlternateNextTD = 0;
2543
2544 TD->TdFlags = 0;
2545 TD->EhciTransfer = NULL;
2546
2547 EhciEndpoint->RemainTDs++;
2548
2549 TD = TD->NextHcdTD;
2550 }
2551
2552 LastTD = TD;
2553 NextTD = LastTD->PhysicalAddress + FIELD_OFFSET(EHCI_HCD_TD, HwTD.NextTD);
2554
2555 PrevTD->HwTD.NextTD = LastTD->PhysicalAddress;
2556 PrevTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress;
2557
2558 PrevTD->NextHcdTD = LastTD;
2559 PrevTD->AltNextHcdTD = LastTD;
2560
2561 if (CurrentTransfer == EhciTransfer)
2562 {
2563 QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
2564
2565 QH->sqh.HwQH.Token.Status = (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE;
2566 QH->sqh.HwQH.Token.TransferBytes = 0;
2567
2568 QH->sqh.HwQH.NextTD = NextTD;
2569 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
2570
2571 return;
2572 }
2573
2574 if (PrevTD->EhciTransfer == CurrentTransfer)
2575 {
2576 if (QH->sqh.HwQH.NextTD == FirstTdPA)
2577 QH->sqh.HwQH.NextTD = NextTD;
2578
2579 if (QH->sqh.HwQH.AlternateNextTD == FirstTdPA)
2580 QH->sqh.HwQH.AlternateNextTD = NextTD;
2581
2582 for (TD = EhciEndpoint->HcdHeadP;
2583 TD;
2584 TD = TD->NextHcdTD)
2585 {
2586 if (TD->EhciTransfer == CurrentTransfer)
2587 {
2588 TD->HwTD.AlternateNextTD = NextTD;
2589 TD->AltNextHcdTD = LastTD;
2590 }
2591 }
2592 }
2593 }
2594 }
2595
2596 VOID
2597 NTAPI
2598 EHCI_AbortTransfer(IN PVOID ehciExtension,
2599 IN PVOID ehciEndpoint,
2600 IN PVOID ehciTransfer,
2601 IN PULONG CompletedLength)
2602 {
2603 PEHCI_EXTENSION EhciExtension = ehciExtension;
2604 PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint;
2605 PEHCI_TRANSFER EhciTransfer = ehciTransfer;
2606 ULONG TransferType;
2607
2608 DPRINT("EHCI_AbortTransfer: EhciTransfer - %p, CompletedLength - %x\n",
2609 EhciTransfer,
2610 CompletedLength);
2611
2612 TransferType = EhciEndpoint->EndpointProperties.TransferType;
2613
2614 if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2615 EHCI_AbortIsoTransfer(EhciExtension, EhciEndpoint, EhciTransfer);
2616 else
2617 EHCI_AbortAsyncTransfer(EhciExtension, EhciEndpoint, EhciTransfer);
2618 }
2619
2620 ULONG
2621 NTAPI
2622 EHCI_GetEndpointState(IN PVOID ehciExtension,
2623 IN PVOID ehciEndpoint)
2624 {
2625 DPRINT1("EHCI_GetEndpointState: UNIMPLEMENTED. FIXME\n");
2626 return 0;
2627 }
2628
2629 VOID
2630 NTAPI
2631 EHCI_RemoveQhFromPeriodicList(IN PEHCI_EXTENSION EhciExtension,
2632 IN PEHCI_ENDPOINT EhciEndpoint)
2633 {
2634 PEHCI_HCD_QH QH;
2635 PEHCI_HCD_QH NextHead;
2636 ULONG NextQhPA;
2637 PEHCI_HCD_QH PrevHead;
2638
2639 QH = EhciEndpoint->QH;
2640
2641 if (!(QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE))
2642 return;
2643
2644 DPRINT("EHCI_RemoveQhFromPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n",
2645 EhciEndpoint,
2646 QH,
2647 EhciEndpoint->StaticQH);
2648
2649 NextHead = QH->sqh.NextHead;
2650 PrevHead = QH->sqh.PrevHead;
2651
2652 PrevHead->sqh.NextHead = NextHead;
2653
2654 if (NextHead)
2655 {
2656 if (!(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC))
2657 NextHead->sqh.PrevHead = PrevHead;
2658
2659 NextQhPA = NextHead->sqh.PhysicalAddress;
2660 NextQhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2661 NextQhPA |= (EHCI_LINK_TYPE_QH << 1);
2662
2663 PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextQhPA;
2664 }
2665 else
2666 {
2667 PrevHead->sqh.HwQH.HorizontalLink.Terminate = 1;
2668 }
2669
2670 QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE;
2671
2672 QH->sqh.NextHead = NULL;
2673 QH->sqh.PrevHead = NULL;
2674 }
2675
2676 VOID
2677 NTAPI
2678 EHCI_RemoveQhFromAsyncList(IN PEHCI_EXTENSION EhciExtension,
2679 IN PEHCI_HCD_QH QH)
2680 {
2681 PEHCI_HCD_QH NextHead;
2682 ULONG NextHeadPA;
2683 PEHCI_HCD_QH PrevHead;
2684 PEHCI_STATIC_QH AsyncHead;
2685 ULONG AsyncHeadPA;
2686
2687 DPRINT("EHCI_RemoveQhFromAsyncList: QH - %p\n", QH);
2688
2689 if (QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE)
2690 {
2691 NextHead = QH->sqh.NextHead;
2692 PrevHead = QH->sqh.PrevHead;
2693
2694 AsyncHead = EhciExtension->AsyncHead;
2695
2696 AsyncHeadPA = AsyncHead->PhysicalAddress;
2697 AsyncHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2698 AsyncHeadPA |= (EHCI_LINK_TYPE_QH << 1);
2699
2700 NextHeadPA = NextHead->sqh.PhysicalAddress;
2701 NextHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2702 NextHeadPA |= (EHCI_LINK_TYPE_QH << 1);
2703
2704 PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextHeadPA;
2705
2706 PrevHead->sqh.NextHead = NextHead;
2707 NextHead->sqh.PrevHead = PrevHead;
2708
2709 EHCI_FlushAsyncCache(EhciExtension);
2710
2711 if (READ_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase) ==
2712 QH->sqh.PhysicalAddress)
2713 {
2714 WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase,
2715 AsyncHeadPA);
2716 }
2717
2718 QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE;
2719 }
2720 }
2721
2722 VOID
2723 NTAPI
2724 EHCI_InsertQhInPeriodicList(IN PEHCI_EXTENSION EhciExtension,
2725 IN PEHCI_ENDPOINT EhciEndpoint)
2726 {
2727 PEHCI_STATIC_QH StaticQH;
2728 PEHCI_HCD_QH QH;
2729 ULONG QhPA;
2730 PEHCI_HCD_QH NextHead;
2731 PEHCI_HCD_QH PrevHead;
2732
2733 QH = EhciEndpoint->QH;
2734 StaticQH = EhciEndpoint->StaticQH;
2735
2736 ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0);
2737 ASSERT(StaticQH->QhFlags & EHCI_QH_FLAG_STATIC);
2738
2739 NextHead = StaticQH->NextHead;
2740
2741 QH->sqh.Period = EhciEndpoint->EndpointProperties.Period;
2742 QH->sqh.Ordinal = EhciEndpoint->EndpointProperties.Reserved6;
2743
2744 DPRINT("EHCI_InsertQhInPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n",
2745 EhciEndpoint,
2746 QH,
2747 EhciEndpoint->StaticQH);
2748
2749 PrevHead = (PEHCI_HCD_QH)StaticQH;
2750
2751 if ((StaticQH->QhFlags & EHCI_QH_FLAG_STATIC) &&
2752 (!NextHead || (NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC)))
2753 {
2754 DPRINT("EHCI_InsertQhInPeriodicList: StaticQH - %p, StaticQH->NextHead - %p\n",
2755 StaticQH,
2756 StaticQH->NextHead);
2757 }
2758 else
2759 {
2760 while (NextHead &&
2761 !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC) &&
2762 QH->sqh.Ordinal > NextHead->sqh.Ordinal)
2763 {
2764 PrevHead = NextHead;
2765 NextHead = NextHead->sqh.NextHead;
2766 }
2767 }
2768
2769 QH->sqh.NextHead = NextHead;
2770 QH->sqh.PrevHead = PrevHead;
2771
2772 if (NextHead && !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC))
2773 NextHead->sqh.PrevHead = QH;
2774
2775 QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE;
2776 QH->sqh.HwQH.HorizontalLink = PrevHead->sqh.HwQH.HorizontalLink;
2777
2778 PrevHead->sqh.NextHead = QH;
2779
2780 QhPA = QH->sqh.PhysicalAddress;
2781 QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2782 QhPA |= (EHCI_LINK_TYPE_QH << 1);
2783
2784 PrevHead->sqh.HwQH.HorizontalLink.AsULONG = QhPA;
2785 }
2786
2787 VOID
2788 NTAPI
2789 EHCI_InsertQhInAsyncList(IN PEHCI_EXTENSION EhciExtension,
2790 IN PEHCI_HCD_QH QH)
2791 {
2792 PEHCI_STATIC_QH AsyncHead;
2793 ULONG QhPA;
2794 PEHCI_HCD_QH NextHead;
2795
2796 DPRINT("EHCI_InsertQhInAsyncList: QH - %p\n", QH);
2797
2798 ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0);
2799 ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_NUKED) == 0);
2800
2801 AsyncHead = EhciExtension->AsyncHead;
2802 NextHead = AsyncHead->NextHead;
2803
2804 QH->sqh.HwQH.HorizontalLink = AsyncHead->HwQH.HorizontalLink;
2805 QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE;
2806 QH->sqh.NextHead = NextHead;
2807 QH->sqh.PrevHead = (PEHCI_HCD_QH)AsyncHead;
2808
2809 NextHead->sqh.PrevHead = QH;
2810
2811 QhPA = QH->sqh.PhysicalAddress;
2812 QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER;
2813 QhPA |= (EHCI_LINK_TYPE_QH << 1);
2814
2815 AsyncHead->HwQH.HorizontalLink.AsULONG = QhPA;
2816
2817 AsyncHead->NextHead = QH;
2818 }
2819
2820 VOID
2821 NTAPI
2822 EHCI_SetIsoEndpointState(IN PEHCI_EXTENSION EhciExtension,
2823 IN PEHCI_ENDPOINT EhciEndpoint,
2824 IN ULONG EndpointState)
2825 {
2826 DPRINT1("EHCI_SetIsoEndpointState: UNIMPLEMENTED. FIXME\n");
2827 }
2828
2829 VOID
2830 NTAPI
2831 EHCI_SetAsyncEndpointState(IN PEHCI_EXTENSION EhciExtension,
2832 IN PEHCI_ENDPOINT EhciEndpoint,
2833 IN ULONG EndpointState)
2834 {
2835 PEHCI_HCD_QH QH;
2836 ULONG TransferType;
2837
2838 DPRINT("EHCI_SetAsyncEndpointState: EhciEndpoint - %p, EndpointState - %x\n",
2839 EhciEndpoint,
2840 EndpointState);
2841
2842 QH = EhciEndpoint->QH;
2843
2844 TransferType = EhciEndpoint->EndpointProperties.TransferType;
2845
2846 switch (EndpointState)
2847 {
2848 case USBPORT_ENDPOINT_PAUSED:
2849 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2850 EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint);
2851 else
2852 EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH);
2853
2854 break;
2855
2856 case USBPORT_ENDPOINT_ACTIVE:
2857 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2858 EHCI_InsertQhInPeriodicList(EhciExtension, EhciEndpoint);
2859 else
2860 EHCI_InsertQhInAsyncList(EhciExtension, EhciEndpoint->QH);
2861
2862 break;
2863
2864 case USBPORT_ENDPOINT_REMOVE:
2865 QH->sqh.QhFlags |= EHCI_QH_FLAG_CLOSED;
2866
2867 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2868 EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint);
2869 else
2870 EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH);
2871
2872 break;
2873
2874 default:
2875 DbgBreakPoint();
2876 break;
2877 }
2878
2879 EhciEndpoint->EndpointState = EndpointState;
2880 }
2881
2882 VOID
2883 NTAPI
2884 EHCI_SetEndpointState(IN PVOID ehciExtension,
2885 IN PVOID ehciEndpoint,
2886 IN ULONG EndpointState)
2887 {
2888 PEHCI_ENDPOINT EhciEndpoint;
2889 ULONG TransferType;
2890
2891 DPRINT("EHCI_SetEndpointState: ... \n");
2892
2893 EhciEndpoint = ehciEndpoint;
2894 TransferType = EhciEndpoint->EndpointProperties.TransferType;
2895
2896 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
2897 TransferType == USBPORT_TRANSFER_TYPE_BULK ||
2898 TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
2899 {
2900 EHCI_SetAsyncEndpointState((PEHCI_EXTENSION)ehciExtension,
2901 EhciEndpoint,
2902 EndpointState);
2903 }
2904 else if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
2905 {
2906 EHCI_SetIsoEndpointState((PEHCI_EXTENSION)ehciExtension,
2907 EhciEndpoint,
2908 EndpointState);
2909 }
2910 else
2911 {
2912 RegPacket.UsbPortBugCheck(ehciExtension);
2913 }
2914 }
2915
2916 VOID
2917 NTAPI
2918 EHCI_InterruptNextSOF(IN PVOID ehciExtension)
2919 {
2920 PEHCI_EXTENSION EhciExtension = ehciExtension;
2921
2922 DPRINT_EHCI("EHCI_InterruptNextSOF: ... \n");
2923
2924 RegPacket.UsbPortInvalidateController(EhciExtension,
2925 USBPORT_INVALIDATE_CONTROLLER_SOFT_INTERRUPT);
2926 }
2927
2928 USBD_STATUS
2929 NTAPI
2930 EHCI_GetErrorFromTD(IN PEHCI_HCD_TD TD)
2931 {
2932 EHCI_TD_TOKEN Token;
2933
2934 DPRINT_EHCI("EHCI_GetErrorFromTD: ... \n");
2935
2936 ASSERT(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED);
2937
2938 Token = TD->HwTD.Token;
2939
2940 if (Token.Status & EHCI_TOKEN_STATUS_TRANSACTION_ERROR)
2941 {
2942 DPRINT("EHCI_GetErrorFromTD: TD - %p, TRANSACTION_ERROR\n", TD);
2943 return USBD_STATUS_XACT_ERROR;
2944 }
2945
2946 if (Token.Status & EHCI_TOKEN_STATUS_BABBLE_DETECTED)
2947 {
2948 DPRINT("EHCI_GetErrorFromTD: TD - %p, BABBLE_DETECTED\n", TD);
2949 return USBD_STATUS_BABBLE_DETECTED;
2950 }
2951
2952 if (Token.Status & EHCI_TOKEN_STATUS_DATA_BUFFER_ERROR)
2953 {
2954 DPRINT("EHCI_GetErrorFromTD: TD - %p, DATA_BUFFER_ERROR\n", TD);
2955 return USBD_STATUS_DATA_BUFFER_ERROR;
2956 }
2957
2958 if (Token.Status & EHCI_TOKEN_STATUS_MISSED_MICROFRAME)
2959 {
2960 DPRINT("EHCI_GetErrorFromTD: TD - %p, MISSED_MICROFRAME\n", TD);
2961 return USBD_STATUS_XACT_ERROR;
2962 }
2963
2964 DPRINT("EHCI_GetErrorFromTD: TD - %p, STALL_PID\n", TD);
2965 return USBD_STATUS_STALL_PID;
2966 }
2967
2968 VOID
2969 NTAPI
2970 EHCI_ProcessDoneAsyncTd(IN PEHCI_EXTENSION EhciExtension,
2971 IN PEHCI_HCD_TD TD)
2972 {
2973 PEHCI_TRANSFER EhciTransfer;
2974 PUSBPORT_TRANSFER_PARAMETERS TransferParameters;
2975 ULONG TransferType;
2976 PEHCI_ENDPOINT EhciEndpoint;
2977 ULONG LengthTransfered;
2978 USBD_STATUS USBDStatus;
2979 PEHCI_HW_REGISTERS OperationalRegs;
2980 EHCI_USB_COMMAND Command;
2981
2982 DPRINT_EHCI("EHCI_ProcessDoneAsyncTd: TD - %p\n", TD);
2983
2984 EhciTransfer = TD->EhciTransfer;
2985
2986 TransferParameters = EhciTransfer->TransferParameters;
2987 EhciTransfer->PendingTDs--;
2988
2989 EhciEndpoint = EhciTransfer->EhciEndpoint;
2990
2991 if (!(TD->TdFlags & EHCI_HCD_TD_FLAG_ACTIVE))
2992 {
2993
2994 if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED)
2995 USBDStatus = EHCI_GetErrorFromTD(TD);
2996 else
2997 USBDStatus = USBD_STATUS_SUCCESS;
2998
2999 LengthTransfered = TD->LengthThisTD - TD->HwTD.Token.TransferBytes;
3000
3001 if (TD->HwTD.Token.PIDCode != EHCI_TD_TOKEN_PID_SETUP)
3002 EhciTransfer->TransferLen += LengthTransfered;
3003
3004 if (USBDStatus != USBD_STATUS_SUCCESS)
3005 EhciTransfer->USBDStatus = USBDStatus;
3006 }
3007
3008 TD->HwTD.NextTD = 0;
3009 TD->HwTD.AlternateNextTD = 0;
3010
3011 TD->TdFlags = 0;
3012 TD->EhciTransfer = NULL;
3013
3014 EhciEndpoint->RemainTDs++;
3015
3016 if (EhciTransfer->PendingTDs == 0)
3017 {
3018 EhciEndpoint->PendingTDs--;
3019
3020 TransferType = EhciEndpoint->EndpointProperties.TransferType;
3021
3022 if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
3023 TransferType == USBPORT_TRANSFER_TYPE_BULK)
3024 {
3025 EhciExtension->PendingTransfers--;
3026
3027 if (EhciExtension->PendingTransfers == 0)
3028 {
3029 OperationalRegs = EhciExtension->OperationalRegs;
3030 Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG);
3031
3032 if (!Command.InterruptAdvanceDoorbell &&
3033 (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT))
3034 {
3035 EHCI_DisableAsyncList(EhciExtension);
3036 }
3037 }
3038 }
3039
3040 RegPacket.UsbPortCompleteTransfer(EhciExtension,
3041 EhciEndpoint,
3042 TransferParameters,
3043 EhciTransfer->USBDStatus,
3044 EhciTransfer->TransferLen);
3045 }
3046 }
3047
3048 VOID
3049 NTAPI
3050 EHCI_PollActiveAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3051 IN PEHCI_ENDPOINT EhciEndpoint)
3052 {
3053 PEHCI_HCD_QH QH;
3054 PEHCI_HCD_TD TD;
3055 PEHCI_HCD_TD CurrentTD;
3056 ULONG CurrentTDPhys;
3057 BOOLEAN IsScheduled;
3058
3059 DPRINT_EHCI("EHCI_PollActiveAsyncEndpoint: ... \n");
3060
3061 QH = EhciEndpoint->QH;
3062
3063 CurrentTDPhys = QH->sqh.HwQH.CurrentTD & LINK_POINTER_MASK;
3064 ASSERT(CurrentTDPhys);
3065
3066 CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTDPhys,
3067 EhciExtension,
3068 EhciEndpoint);
3069
3070 if (CurrentTD == EhciEndpoint->DmaBufferVA)
3071 return;
3072
3073 IsScheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE;
3074
3075 if (!EHCI_HardwarePresent(EhciExtension, 0))
3076 IsScheduled = 0;
3077
3078 TD = EhciEndpoint->HcdHeadP;
3079
3080 if (TD == CurrentTD)
3081 {
3082 if (TD != EhciEndpoint->HcdTailP &&
3083 !(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE))
3084 {
3085 if (TD->NextHcdTD && TD->HwTD.NextTD != TD->NextHcdTD->PhysicalAddress)
3086 TD->HwTD.NextTD = TD->NextHcdTD->PhysicalAddress;
3087
3088 if (TD->AltNextHcdTD &&
3089 TD->HwTD.AlternateNextTD != TD->AltNextHcdTD->PhysicalAddress)
3090 {
3091 TD->HwTD.AlternateNextTD = TD->AltNextHcdTD->PhysicalAddress;
3092 }
3093
3094 if (QH->sqh.HwQH.CurrentTD == TD->PhysicalAddress &&
3095 !(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) &&
3096 (QH->sqh.HwQH.NextTD != TD->HwTD.NextTD ||
3097 QH->sqh.HwQH.AlternateNextTD != TD->HwTD.AlternateNextTD))
3098 {
3099 QH->sqh.HwQH.NextTD = TD->HwTD.NextTD;
3100 QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD;
3101 }
3102
3103 EHCI_InterruptNextSOF(EhciExtension);
3104 }
3105 }
3106 else
3107 {
3108 while (TD != CurrentTD)
3109 {
3110 ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0);
3111
3112 TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3113
3114 if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3115 TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3116
3117 InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3118 TD = TD->NextHcdTD;
3119 }
3120 }
3121
3122 if (CurrentTD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3123 {
3124 ASSERT(TD != NULL);
3125 EhciEndpoint->HcdHeadP = TD;
3126 return;
3127 }
3128
3129 if ((CurrentTD->NextHcdTD != EhciEndpoint->HcdTailP) &&
3130 (CurrentTD->AltNextHcdTD != EhciEndpoint->HcdTailP ||
3131 CurrentTD->HwTD.Token.TransferBytes == 0))
3132 {
3133 ASSERT(TD != NULL);
3134 EhciEndpoint->HcdHeadP = TD;
3135 return;
3136 }
3137
3138 if (IsScheduled)
3139 {
3140 EHCI_LockQH(EhciExtension,
3141 QH,
3142 EhciEndpoint->EndpointProperties.TransferType);
3143 }
3144
3145 QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
3146
3147 CurrentTD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3148 InsertTailList(&EhciEndpoint->ListTDs, &CurrentTD->DoneLink);
3149
3150 if (CurrentTD->HwTD.Token.TransferBytes &&
3151 CurrentTD->AltNextHcdTD == EhciEndpoint->HcdTailP)
3152 {
3153 TD = CurrentTD->NextHcdTD;
3154
3155 while (TD != EhciEndpoint->HcdTailP)
3156 {
3157 TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3158 InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3159 TD = TD->NextHcdTD;
3160 }
3161 }
3162
3163 QH->sqh.HwQH.CurrentTD = EhciEndpoint->HcdTailP->PhysicalAddress;
3164 QH->sqh.HwQH.NextTD = TERMINATE_POINTER;
3165 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
3166 QH->sqh.HwQH.Token.TransferBytes = 0;
3167
3168 EhciEndpoint->HcdHeadP = EhciEndpoint->HcdTailP;
3169
3170 if (IsScheduled)
3171 EHCI_UnlockQH(EhciExtension, QH);
3172 }
3173
3174 VOID
3175 NTAPI
3176 EHCI_PollHaltedAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3177 IN PEHCI_ENDPOINT EhciEndpoint)
3178 {
3179 PEHCI_HCD_QH QH;
3180 PEHCI_HCD_TD CurrentTD;
3181 ULONG CurrentTdPA;
3182 PEHCI_HCD_TD TD;
3183 PEHCI_TRANSFER Transfer;
3184 BOOLEAN IsScheduled;
3185
3186 DPRINT("EHCI_PollHaltedAsyncEndpoint: EhciEndpoint - %p\n", EhciEndpoint);
3187
3188 QH = EhciEndpoint->QH;
3189 EHCI_DumpHwQH(QH);
3190
3191 CurrentTdPA = QH->sqh.HwQH.CurrentTD & LINK_POINTER_MASK;
3192 ASSERT(CurrentTdPA);
3193
3194 IsScheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE;
3195
3196 if (!EHCI_HardwarePresent(EhciExtension, 0))
3197 IsScheduled = 0;
3198
3199 CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTdPA,
3200 EhciExtension,
3201 EhciEndpoint);
3202
3203 DPRINT("EHCI_PollHaltedAsyncEndpoint: CurrentTD - %p\n", CurrentTD);
3204
3205 if (CurrentTD == EhciEndpoint->DmaBufferVA)
3206 return;
3207
3208 ASSERT(EhciEndpoint->HcdTailP != CurrentTD);
3209
3210 if (IsScheduled)
3211 {
3212 EHCI_LockQH(EhciExtension,
3213 QH,
3214 EhciEndpoint->EndpointProperties.TransferType);
3215 }
3216
3217 TD = EhciEndpoint->HcdHeadP;
3218
3219 while (TD != CurrentTD)
3220 {
3221 DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD);
3222
3223 ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0);
3224
3225 if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3226 TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3227
3228 TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3229
3230 InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3231
3232 TD = TD->NextHcdTD;
3233 }
3234
3235 TD = CurrentTD;
3236
3237 Transfer = CurrentTD->EhciTransfer;
3238
3239 do
3240 {
3241 DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD);
3242
3243 if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE)
3244 TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE;
3245
3246 TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE;
3247
3248 InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink);
3249
3250 TD = TD->NextHcdTD;
3251 }
3252 while (TD->EhciTransfer == Transfer);
3253
3254 EhciEndpoint->HcdHeadP = TD;
3255
3256 QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA;
3257 QH->sqh.HwQH.NextTD = TD->PhysicalAddress;
3258 QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER;
3259 QH->sqh.HwQH.Token.TransferBytes = 0;
3260
3261 if (IsScheduled)
3262 EHCI_UnlockQH(EhciExtension, QH);
3263
3264 if (EhciEndpoint->EndpointStatus & USBPORT_ENDPOINT_CONTROL)
3265 {
3266 EhciEndpoint->EndpointStatus &= ~USBPORT_ENDPOINT_HALT;
3267 QH->sqh.HwQH.Token.ErrorCounter = 0;
3268 QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE |
3269 EHCI_TOKEN_STATUS_HALTED);
3270
3271 }
3272 }
3273
3274 VOID
3275 NTAPI
3276 EHCI_PollAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension,
3277 IN PEHCI_ENDPOINT EhciEndpoint)
3278 {
3279 PEHCI_HCD_QH QH;