8bf9ca9cf7cfc7eb6e310940e6f06c3cdd83df70
[reactos.git] / drivers / usb / usbport / endpoint.c
1 /*
2 * PROJECT: ReactOS USB Port Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: USBPort endpoint functions
5 * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6 */
7
8 #include "usbport.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define NDEBUG_USBPORT_CORE
14 #include "usbdebug.h"
15
16 ULONG
17 NTAPI
18 USBPORT_CalculateUsbBandwidth(IN PDEVICE_OBJECT FdoDevice,
19 IN PUSBPORT_ENDPOINT Endpoint)
20 {
21 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
22 ULONG Bandwidth;
23 ULONG Overhead;
24
25 DPRINT("USBPORT_CalculateUsbBandwidth ... \n");
26
27 EndpointProperties = &Endpoint->EndpointProperties;
28
29 switch (EndpointProperties->TransferType)
30 {
31 case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
32 Overhead = USB2_FS_ISOCHRONOUS_OVERHEAD;
33 break;
34
35 case USBPORT_TRANSFER_TYPE_INTERRUPT:
36 Overhead = USB2_FS_INTERRUPT_OVERHEAD;
37 break;
38
39 default: //USBPORT_TRANSFER_TYPE_CONTROL or USBPORT_TRANSFER_TYPE_BULK
40 Overhead = 0;
41 break;
42 }
43
44 if (Overhead == 0)
45 {
46 Bandwidth = 0;
47 }
48 else
49 {
50 Bandwidth = (EndpointProperties->TotalMaxPacketSize + Overhead) * 8 * 7 / 6;
51 }
52
53 if (EndpointProperties->DeviceSpeed == UsbLowSpeed)
54 {
55 Bandwidth *= 8;
56 }
57
58 return Bandwidth;
59 }
60
61 BOOLEAN
62 NTAPI
63 USBPORT_AllocateBandwidth(IN PDEVICE_OBJECT FdoDevice,
64 IN PUSBPORT_ENDPOINT Endpoint)
65 {
66 PUSBPORT_DEVICE_EXTENSION FdoExtension;
67 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
68 ULONG TransferType;
69 ULONG TotalBusBandwidth;
70 ULONG EndpointBandwidth;
71 ULONG MinBandwidth;
72 PULONG Bandwidth;
73 ULONG MaxBandwidth = 0;
74 ULONG ix;
75 ULONG Offset;
76 LONG ScheduleOffset = -1;
77 ULONG Period;
78 ULONG Factor;
79 UCHAR Bit;
80
81 DPRINT("USBPORT_AllocateBandwidth: FdoDevice - %p, Endpoint - %p\n",
82 FdoDevice,
83 Endpoint);
84
85 FdoExtension = FdoDevice->DeviceExtension;
86 EndpointProperties = &Endpoint->EndpointProperties;
87 TransferType = EndpointProperties->TransferType;
88
89 if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
90 TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
91 Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
92 {
93 EndpointProperties->ScheduleOffset = 0;
94 return TRUE;
95 }
96
97 TotalBusBandwidth = FdoExtension->TotalBusBandwidth;
98 EndpointBandwidth = EndpointProperties->UsbBandwidth;
99 Period = EndpointProperties->Period;
100 Factor = USB2_FRAMES / Period;
101 ASSERT(Factor);
102
103 for (Offset = 0; Offset < Period; Offset++)
104 {
105 MinBandwidth = TotalBusBandwidth;
106 Bandwidth = &FdoExtension->Bandwidth[Offset * Factor];
107
108 for (ix = 1; *Bandwidth >= EndpointBandwidth; ix++)
109 {
110 if (MinBandwidth > *Bandwidth)
111 {
112 MinBandwidth = *Bandwidth;
113 }
114
115 Bandwidth++;
116
117 if (Factor <= ix)
118 {
119 if (MinBandwidth > MaxBandwidth)
120 {
121 MaxBandwidth = MinBandwidth;
122 ScheduleOffset = Offset;
123
124 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n",
125 ScheduleOffset);
126 }
127
128 break;
129 }
130 }
131 }
132
133 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n", ScheduleOffset);
134
135 if (ScheduleOffset != -1)
136 {
137 EndpointProperties->ScheduleOffset = ScheduleOffset;
138
139 Bandwidth = &FdoExtension->Bandwidth[ScheduleOffset * Factor];
140
141 for (Factor = USB2_FRAMES / Period; Factor; Factor--)
142 {
143 FdoExtension->Bandwidth[ScheduleOffset * Factor] -= EndpointBandwidth;
144 }
145
146 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
147 {
148 for (Bit = 0x80; Bit != 0; Bit >>= 1)
149 {
150 if ((Period & Bit) != 0)
151 {
152 Period = Bit;
153 break;
154 }
155 }
156
157 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedInterrupt_XXms\n");
158 }
159 else
160 {
161 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedIso\n");
162 }
163 }
164
165 DPRINT("USBPORT_AllocateBandwidth: FIXME USBPORT_UpdateAllocatedBw\n");
166
167 DPRINT("USBPORT_AllocateBandwidth: ScheduleOffset - %X\n", ScheduleOffset);
168 return ScheduleOffset != -1;
169 }
170
171 VOID
172 NTAPI
173 USBPORT_FreeBandwidth(IN PDEVICE_OBJECT FdoDevice,
174 IN PUSBPORT_ENDPOINT Endpoint)
175 {
176 PUSBPORT_DEVICE_EXTENSION FdoExtension;
177 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
178 ULONG TransferType;
179 ULONG Offset;
180 ULONG EndpointBandwidth;
181 ULONG Period;
182 ULONG Factor;
183 UCHAR Bit;
184
185 DPRINT("USBPORT_FreeBandwidth: FdoDevice - %p, Endpoint - %p\n",
186 FdoDevice,
187 Endpoint);
188
189 FdoExtension = FdoDevice->DeviceExtension;
190
191 EndpointProperties = &Endpoint->EndpointProperties;
192 TransferType = EndpointProperties->TransferType;
193
194 if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
195 TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
196 (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
197 {
198 return;
199 }
200
201 Offset = Endpoint->EndpointProperties.ScheduleOffset;
202 EndpointBandwidth = Endpoint->EndpointProperties.UsbBandwidth;
203 Period = Endpoint->EndpointProperties.Period;
204
205 ASSERT(USB2_FRAMES / Period);
206
207 for (Factor = USB2_FRAMES / Period; Factor; Factor--)
208 {
209 FdoExtension->Bandwidth[Offset * Factor] += EndpointBandwidth;
210 }
211
212 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
213 {
214 for (Bit = 0x80; Bit != 0; Bit >>= 1)
215 {
216 if ((Period & Bit) != 0)
217 {
218 Period = Bit;
219 break;
220 }
221 }
222
223 ASSERT(Period != 0);
224
225 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedInterrupt_XXms\n");
226 }
227 else
228 {
229 DPRINT("USBPORT_AllocateBandwidth: FIXME AllocedIso\n");
230 }
231
232 DPRINT1("USBPORT_FreeBandwidth: FIXME USBPORT_UpdateAllocatedBw\n");
233 }
234
235 UCHAR
236 NTAPI
237 USBPORT_NormalizeHsInterval(UCHAR Interval)
238 {
239 UCHAR interval;
240
241 DPRINT("USBPORT_NormalizeHsInterval: Interval - %x\n", Interval);
242
243 interval = Interval;
244
245 if (Interval)
246 interval = Interval - 1;
247
248 if (interval > 5)
249 interval = 5;
250
251 return 1 << interval;
252 }
253
254 BOOLEAN
255 NTAPI
256 USBPORT_EndpointHasQueuedTransfers(IN PDEVICE_OBJECT FdoDevice,
257 IN PUSBPORT_ENDPOINT Endpoint,
258 IN PULONG TransferCount)
259 {
260 PLIST_ENTRY Entry;
261 PUSBPORT_TRANSFER Transfer;
262 BOOLEAN Result = FALSE;
263
264 DPRINT_CORE("USBPORT_EndpointHasQueuedTransfers: ... \n");
265
266 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
267
268 if (!IsListEmpty(&Endpoint->PendingTransferList))
269 Result = TRUE;
270
271 if (!IsListEmpty(&Endpoint->TransferList))
272 {
273 Result = TRUE;
274
275 if (TransferCount)
276 {
277 *TransferCount = 0;
278
279 for (Entry = Endpoint->TransferList.Flink;
280 Entry && Entry != &Endpoint->TransferList;
281 Entry = Transfer->TransferLink.Flink)
282 {
283 Transfer = CONTAINING_RECORD(Entry,
284 USBPORT_TRANSFER,
285 TransferLink);
286
287 if (Transfer->Flags & TRANSFER_FLAG_SUBMITED)
288 {
289 ++*TransferCount;
290 }
291 }
292 }
293 }
294
295 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
296
297 return Result;
298 }
299
300 VOID
301 NTAPI
302 USBPORT_NukeAllEndpoints(IN PDEVICE_OBJECT FdoDevice)
303 {
304 PUSBPORT_DEVICE_EXTENSION FdoExtension;
305 PLIST_ENTRY EndpointList;
306 PUSBPORT_ENDPOINT Endpoint;
307 KIRQL OldIrql;
308
309 DPRINT("USBPORT_NukeAllEndpoints \n");
310
311 FdoExtension = FdoDevice->DeviceExtension;
312
313 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
314
315 EndpointList = FdoExtension->EndpointList.Flink;
316
317 while (EndpointList && (EndpointList != &FdoExtension->EndpointList))
318 {
319 Endpoint = CONTAINING_RECORD(EndpointList,
320 USBPORT_ENDPOINT,
321 EndpointLink);
322
323 if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
324 Endpoint->Flags |= ENDPOINT_FLAG_NUKE;
325
326 EndpointList = Endpoint->EndpointLink.Flink;
327 }
328
329 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
330 }
331
332 ULONG
333 NTAPI
334 USBPORT_GetEndpointState(IN PUSBPORT_ENDPOINT Endpoint)
335 {
336 ULONG State;
337
338 //DPRINT("USBPORT_GetEndpointState \n");
339
340 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
341
342 if (Endpoint->StateLast != Endpoint->StateNext)
343 {
344 State = USBPORT_ENDPOINT_UNKNOWN;
345 }
346 else
347 {
348 State = Endpoint->StateLast;
349 }
350
351 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
352
353 if (State != USBPORT_ENDPOINT_ACTIVE)
354 {
355 DPRINT("USBPORT_GetEndpointState: Endpoint - %p, State - %x\n",
356 Endpoint,
357 State);
358 }
359
360 return State;
361 }
362
363 VOID
364 NTAPI
365 USBPORT_SetEndpointState(IN PUSBPORT_ENDPOINT Endpoint,
366 IN ULONG State)
367 {
368 PDEVICE_OBJECT FdoDevice;
369 PUSBPORT_DEVICE_EXTENSION FdoExtension;
370 PUSBPORT_REGISTRATION_PACKET Packet;
371 KIRQL OldIrql;
372
373 DPRINT("USBPORT_SetEndpointState: Endpoint - %p, State - %x\n",
374 Endpoint,
375 State);
376
377 FdoDevice = Endpoint->FdoDevice;
378 FdoExtension = FdoDevice->DeviceExtension;
379 Packet = &FdoExtension->MiniPortInterface->Packet;
380
381 KeAcquireSpinLock(&Endpoint->StateChangeSpinLock,
382 &Endpoint->EndpointStateOldIrql);
383
384 if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
385 {
386 if (Endpoint->Flags & ENDPOINT_FLAG_NUKE)
387 {
388 Endpoint->StateLast = State;
389 Endpoint->StateNext = State;
390
391 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
392 Endpoint->EndpointStateOldIrql);
393
394 USBPORT_InvalidateEndpointHandler(FdoDevice,
395 Endpoint,
396 INVALIDATE_ENDPOINT_WORKER_THREAD);
397 return;
398 }
399
400 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
401 Endpoint->EndpointStateOldIrql);
402
403 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
404 Packet->SetEndpointState(FdoExtension->MiniPortExt,
405 Endpoint + 1,
406 State);
407 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
408
409 Endpoint->StateNext = State;
410
411 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
412 Endpoint->FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
413 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
414
415 ExInterlockedInsertTailList(&FdoExtension->EpStateChangeList,
416 &Endpoint->StateChangeLink,
417 &FdoExtension->EpStateChangeSpinLock);
418
419 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
420 Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
421 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
422 }
423 else
424 {
425 Endpoint->StateLast = State;
426 Endpoint->StateNext = State;
427
428 if (State == USBPORT_ENDPOINT_REMOVE)
429 {
430 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
431 Endpoint->EndpointStateOldIrql);
432
433 USBPORT_InvalidateEndpointHandler(FdoDevice,
434 Endpoint,
435 INVALIDATE_ENDPOINT_WORKER_THREAD);
436 return;
437 }
438
439 KeReleaseSpinLock(&Endpoint->StateChangeSpinLock,
440 Endpoint->EndpointStateOldIrql);
441 }
442 }
443
444 VOID
445 NTAPI
446 USBPORT_AddPipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
447 IN PUSBPORT_PIPE_HANDLE PipeHandle)
448 {
449 DPRINT("USBPORT_AddPipeHandle: DeviceHandle - %p, PipeHandle - %p\n",
450 DeviceHandle,
451 PipeHandle);
452
453 InsertTailList(&DeviceHandle->PipeHandleList, &PipeHandle->PipeLink);
454 }
455
456 VOID
457 NTAPI
458 USBPORT_RemovePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
459 IN PUSBPORT_PIPE_HANDLE PipeHandle)
460 {
461 DPRINT("USBPORT_RemovePipeHandle: PipeHandle - %p\n", PipeHandle);
462
463 RemoveEntryList(&PipeHandle->PipeLink);
464
465 PipeHandle->PipeLink.Flink = NULL;
466 PipeHandle->PipeLink.Blink = NULL;
467 }
468
469 BOOLEAN
470 NTAPI
471 USBPORT_ValidatePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
472 IN PUSBPORT_PIPE_HANDLE PipeHandle)
473 {
474 PLIST_ENTRY HandleList;
475 PUSBPORT_PIPE_HANDLE CurrentHandle;
476
477 //DPRINT("USBPORT_ValidatePipeHandle: DeviceHandle - %p, PipeHandle - %p\n",
478 // DeviceHandle,
479 // PipeHandle);
480
481 HandleList = DeviceHandle->PipeHandleList.Flink;
482
483 while (HandleList != &DeviceHandle->PipeHandleList)
484 {
485 CurrentHandle = CONTAINING_RECORD(HandleList,
486 USBPORT_PIPE_HANDLE,
487 PipeLink);
488
489 HandleList = HandleList->Flink;
490
491 if (CurrentHandle == PipeHandle)
492 return TRUE;
493 }
494
495 return FALSE;
496 }
497
498 BOOLEAN
499 NTAPI
500 USBPORT_DeleteEndpoint(IN PDEVICE_OBJECT FdoDevice,
501 IN PUSBPORT_ENDPOINT Endpoint)
502 {
503 PUSBPORT_DEVICE_EXTENSION FdoExtension;
504 BOOLEAN Result;
505 KIRQL OldIrql;
506
507 DPRINT1("USBPORT_DeleteEndpoint: Endpoint - %p\n", Endpoint);
508
509 FdoExtension = FdoDevice->DeviceExtension;
510
511 if ((Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink) ||
512 Endpoint->LockCounter != -1)
513 {
514 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
515
516 ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
517 &Endpoint->CloseLink,
518 &FdoExtension->EndpointClosedSpinLock);
519
520 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
521
522 Result = FALSE;
523 }
524 else
525 {
526 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
527
528 RemoveEntryList(&Endpoint->EndpointLink);
529 Endpoint->EndpointLink.Flink = NULL;
530 Endpoint->EndpointLink.Blink = NULL;
531
532 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
533
534 MiniportCloseEndpoint(FdoDevice, Endpoint);
535
536 if (Endpoint->HeaderBuffer)
537 {
538 USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer);
539 }
540
541 ExFreePoolWithTag(Endpoint, USB_PORT_TAG);
542
543 Result = TRUE;
544 }
545
546 return Result;
547 }
548
549 VOID
550 NTAPI
551 MiniportCloseEndpoint(IN PDEVICE_OBJECT FdoDevice,
552 IN PUSBPORT_ENDPOINT Endpoint)
553 {
554 PUSBPORT_DEVICE_EXTENSION FdoExtension;
555 PUSBPORT_REGISTRATION_PACKET Packet;
556 BOOLEAN IsDoDisablePeriodic;
557 ULONG TransferType;
558 KIRQL OldIrql;
559
560 DPRINT("MiniportCloseEndpoint: Endpoint - %p\n", Endpoint);
561
562 FdoExtension = FdoDevice->DeviceExtension;
563 Packet = &FdoExtension->MiniPortInterface->Packet;
564
565 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
566
567 if (Endpoint->Flags & ENDPOINT_FLAG_OPENED)
568 {
569 TransferType = Endpoint->EndpointProperties.TransferType;
570
571 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT ||
572 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
573 {
574 --FdoExtension->PeriodicEndpoints;
575 }
576
577 IsDoDisablePeriodic = FdoExtension->PeriodicEndpoints == 0;
578
579 Packet->CloseEndpoint(FdoExtension->MiniPortExt,
580 Endpoint + 1,
581 IsDoDisablePeriodic);
582
583 Endpoint->Flags &= ~ENDPOINT_FLAG_OPENED;
584 Endpoint->Flags |= ENDPOINT_FLAG_CLOSED;
585 }
586
587 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
588 }
589
590 VOID
591 NTAPI
592 USBPORT_ClosePipe(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
593 IN PDEVICE_OBJECT FdoDevice,
594 IN PUSBPORT_PIPE_HANDLE PipeHandle)
595 {
596 PUSBPORT_DEVICE_EXTENSION FdoExtension;
597 PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
598 PUSBPORT_ENDPOINT Endpoint;
599 PUSBPORT_REGISTRATION_PACKET Packet;
600 PUSB2_TT_EXTENSION TtExtension;
601 ULONG ix;
602 BOOLEAN IsReady;
603 KIRQL OldIrql;
604
605 DPRINT1("USBPORT_ClosePipe \n");
606
607 FdoExtension = FdoDevice->DeviceExtension;
608
609 if (PipeHandle->Flags & PIPE_HANDLE_FLAG_CLOSED)
610 return;
611
612 USBPORT_RemovePipeHandle(DeviceHandle, PipeHandle);
613
614 PipeHandle->Flags |= PIPE_HANDLE_FLAG_CLOSED;
615
616 if (PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE)
617 {
618 PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_NULL_PACKET_SIZE;
619 return;
620 }
621
622 Endpoint = PipeHandle->Endpoint;
623
624 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
625
626 if ((Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) &&
627 (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT))
628 {
629 PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
630 PdoExtension->Endpoint = NULL;
631 }
632
633 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
634
635 while (TRUE)
636 {
637 IsReady = TRUE;
638
639 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
640 &Endpoint->EndpointOldIrql);
641
642 if (!IsListEmpty(&Endpoint->PendingTransferList))
643 IsReady = FALSE;
644
645 if (!IsListEmpty(&Endpoint->TransferList))
646 IsReady = FALSE;
647
648 if (!IsListEmpty(&Endpoint->CancelList))
649 IsReady = FALSE;
650
651 if (!IsListEmpty(&Endpoint->AbortList))
652 IsReady = FALSE;
653
654 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
655 if (Endpoint->StateLast != Endpoint->StateNext)
656 IsReady = FALSE;
657 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
658
659 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
660 Endpoint->EndpointOldIrql);
661
662 if (InterlockedIncrement(&Endpoint->LockCounter))
663 IsReady = FALSE;
664 InterlockedDecrement(&Endpoint->LockCounter);
665
666 if (IsReady == TRUE)
667 break;
668
669 USBPORT_Wait(FdoDevice, 1);
670 }
671
672 Endpoint->DeviceHandle = NULL;
673 Packet = &FdoExtension->MiniPortInterface->Packet;
674
675 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
676 {
677 USBPORT_FreeBandwidthUSB2(FdoDevice, Endpoint);
678
679 KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql);
680
681 TtExtension = Endpoint->TtExtension;
682 DPRINT1("USBPORT_ClosePipe: TtExtension - %p\n", TtExtension);
683
684 if (TtExtension)
685 {
686 RemoveEntryList(&Endpoint->TtLink);
687
688 Endpoint->TtLink.Flink = NULL;
689 Endpoint->TtLink.Blink = NULL;
690
691 if (TtExtension->Flags & USB2_TT_EXTENSION_FLAG_DELETED)
692 {
693 if (IsListEmpty(&TtExtension->EndpointList))
694 {
695 USBPORT_UpdateAllocatedBwTt(TtExtension);
696
697 for (ix = 0; ix < USB2_FRAMES; ix++)
698 {
699 FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
700 }
701
702 DPRINT1("USBPORT_ClosePipe: ExFreePoolWithTag TtExtension - %p\n", TtExtension);
703 ExFreePoolWithTag(TtExtension, USB_PORT_TAG);
704 }
705 }
706 }
707
708 KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql);
709 }
710 else
711 {
712 USBPORT_FreeBandwidth(FdoDevice, Endpoint);
713 }
714
715 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
716 USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_REMOVE);
717 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
718
719 USBPORT_SignalWorkerThread(FdoDevice);
720 }
721
722 MPSTATUS
723 NTAPI
724 MiniportOpenEndpoint(IN PDEVICE_OBJECT FdoDevice,
725 IN PUSBPORT_ENDPOINT Endpoint)
726 {
727 PUSBPORT_DEVICE_EXTENSION FdoExtension;
728 PUSBPORT_REGISTRATION_PACKET Packet;
729 KIRQL OldIrql;
730 ULONG TransferType;
731 MPSTATUS MpStatus;
732
733 DPRINT("MiniportOpenEndpoint: Endpoint - %p\n", Endpoint);
734
735 FdoExtension = FdoDevice->DeviceExtension;
736 Packet = &FdoExtension->MiniPortInterface->Packet;
737
738 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
739
740 Endpoint->Flags &= ~ENDPOINT_FLAG_CLOSED;
741
742 MpStatus = Packet->OpenEndpoint(FdoExtension->MiniPortExt,
743 &Endpoint->EndpointProperties,
744 Endpoint + 1);
745
746 if (!MpStatus)
747 {
748 TransferType = Endpoint->EndpointProperties.TransferType;
749
750 if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT ||
751 TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
752 {
753 ++FdoExtension->PeriodicEndpoints;
754 }
755
756 Endpoint->Flags |= ENDPOINT_FLAG_OPENED;
757 }
758
759 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
760 return MpStatus;
761 }
762
763 NTSTATUS
764 NTAPI
765 USBPORT_OpenPipe(IN PDEVICE_OBJECT FdoDevice,
766 IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
767 IN PUSBPORT_PIPE_HANDLE PipeHandle,
768 IN OUT PUSBD_STATUS UsbdStatus)
769 {
770 PUSBPORT_DEVICE_EXTENSION FdoExtension;
771 PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
772 PUSBPORT_REGISTRATION_PACKET Packet;
773 ULONG EndpointSize;
774 PUSBPORT_ENDPOINT Endpoint;
775 PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
776 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
777 UCHAR Direction;
778 UCHAR Interval;
779 UCHAR Period;
780 USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0};
781 PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer;
782 MPSTATUS MpStatus;
783 USBD_STATUS USBDStatus;
784 NTSTATUS Status;
785 KIRQL OldIrql;
786 USHORT MaxPacketSize;
787 USHORT AdditionalTransaction;
788 BOOLEAN IsAllocatedBandwidth;
789
790 DPRINT1("USBPORT_OpenPipe: DeviceHandle - %p, FdoDevice - %p, PipeHandle - %p\n",
791 DeviceHandle,
792 FdoDevice,
793 PipeHandle);
794
795 FdoExtension = FdoDevice->DeviceExtension;
796 Packet = &FdoExtension->MiniPortInterface->Packet;
797
798 EndpointSize = sizeof(USBPORT_ENDPOINT) + Packet->MiniPortEndpointSize;
799
800 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
801 {
802 EndpointSize += sizeof(USB2_TT_ENDPOINT);
803 }
804
805 if (PipeHandle->EndpointDescriptor.wMaxPacketSize == 0)
806 {
807 USBPORT_AddPipeHandle(DeviceHandle, PipeHandle);
808
809 PipeHandle->Flags = (PipeHandle->Flags & ~PIPE_HANDLE_FLAG_CLOSED) |
810 PIPE_HANDLE_FLAG_NULL_PACKET_SIZE;
811
812 PipeHandle->Endpoint = (PUSBPORT_ENDPOINT)-1;
813
814 return STATUS_SUCCESS;
815 }
816
817 Endpoint = ExAllocatePoolWithTag(NonPagedPool, EndpointSize, USB_PORT_TAG);
818
819 if (!Endpoint)
820 {
821 DPRINT1("USBPORT_OpenPipe: Not allocated Endpoint!\n");
822 Status = STATUS_INSUFFICIENT_RESOURCES;
823 return Status;
824 }
825
826 RtlZeroMemory(Endpoint, EndpointSize);
827
828 Endpoint->FdoDevice = FdoDevice;
829 Endpoint->DeviceHandle = DeviceHandle;
830 Endpoint->LockCounter = -1;
831
832 Endpoint->TtExtension = DeviceHandle->TtExtension;
833
834 if (DeviceHandle->TtExtension)
835 {
836 ExInterlockedInsertTailList(&DeviceHandle->TtExtension->EndpointList,
837 &Endpoint->TtLink,
838 &FdoExtension->TtSpinLock);
839 }
840
841 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
842 {
843 Endpoint->TtEndpoint = (PUSB2_TT_ENDPOINT)((ULONG_PTR)Endpoint +
844 sizeof(USBPORT_ENDPOINT) +
845 Packet->MiniPortEndpointSize);
846 }
847 else
848 {
849 Endpoint->TtEndpoint = NULL;
850 }
851
852 KeInitializeSpinLock(&Endpoint->EndpointSpinLock);
853 KeInitializeSpinLock(&Endpoint->StateChangeSpinLock);
854
855 InitializeListHead(&Endpoint->PendingTransferList);
856 InitializeListHead(&Endpoint->TransferList);
857 InitializeListHead(&Endpoint->CancelList);
858 InitializeListHead(&Endpoint->AbortList);
859
860 EndpointProperties = &Endpoint->EndpointProperties;
861 EndpointDescriptor = &PipeHandle->EndpointDescriptor;
862
863 MaxPacketSize = EndpointDescriptor->wMaxPacketSize & 0x7FF;
864 AdditionalTransaction = (EndpointDescriptor->wMaxPacketSize >> 11) & 3;
865
866 EndpointProperties->DeviceAddress = DeviceHandle->DeviceAddress;
867 EndpointProperties->DeviceSpeed = DeviceHandle->DeviceSpeed;
868 EndpointProperties->Period = 0;
869 EndpointProperties->EndpointAddress = EndpointDescriptor->bEndpointAddress;
870 EndpointProperties->TransactionPerMicroframe = AdditionalTransaction + 1;
871 EndpointProperties->MaxPacketSize = MaxPacketSize;
872 EndpointProperties->TotalMaxPacketSize = MaxPacketSize *
873 (AdditionalTransaction + 1);
874
875 if (Endpoint->TtExtension)
876 {
877 EndpointProperties->HubAddr = Endpoint->TtExtension->DeviceAddress;
878 }
879 else
880 {
881 EndpointProperties->HubAddr = -1;
882 }
883
884 EndpointProperties->PortNumber = DeviceHandle->PortNumber;
885
886 switch (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK)
887 {
888 case USB_ENDPOINT_TYPE_CONTROL:
889 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_CONTROL;
890
891 if (EndpointProperties->EndpointAddress == 0)
892 {
893 EndpointProperties->MaxTransferSize = 0x1000; // OUT Ep0
894 }
895 else
896 {
897 EndpointProperties->MaxTransferSize = 0x10000;
898 }
899
900 break;
901
902 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
903 DPRINT1("USBPORT_OpenPipe: USB_ENDPOINT_TYPE_ISOCHRONOUS UNIMPLEMENTED. FIXME. \n");
904 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_ISOCHRONOUS;
905 EndpointProperties->MaxTransferSize = 0x1000000;
906 break;
907
908 case USB_ENDPOINT_TYPE_BULK:
909 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_BULK;
910 EndpointProperties->MaxTransferSize = 0x10000;
911 break;
912
913 case USB_ENDPOINT_TYPE_INTERRUPT:
914 EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_INTERRUPT;
915 EndpointProperties->MaxTransferSize = 0x400;
916 break;
917 }
918
919 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
920 {
921 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
922 {
923 Interval = USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval);
924 }
925 else
926 {
927 Interval = EndpointDescriptor->bInterval;
928 }
929
930 EndpointProperties->Period = ENDPOINT_INTERRUPT_32ms;
931
932 if (Interval && (Interval < USB2_FRAMES))
933 {
934 if ((EndpointProperties->DeviceSpeed != UsbLowSpeed) ||
935 (Interval >= ENDPOINT_INTERRUPT_8ms))
936 {
937 if (!(Interval & ENDPOINT_INTERRUPT_32ms))
938 {
939 Period = EndpointProperties->Period;
940
941 do
942 {
943 Period >>= 1;
944 }
945 while (!(Period & Interval));
946
947 EndpointProperties->Period = Period;
948 }
949 }
950 else
951 {
952 EndpointProperties->Period = ENDPOINT_INTERRUPT_8ms;
953 }
954 }
955 }
956
957 if (EndpointProperties->TransferType == USB_ENDPOINT_TYPE_ISOCHRONOUS)
958 {
959 if (EndpointProperties->DeviceSpeed == UsbHighSpeed)
960 {
961 EndpointProperties->Period =
962 USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval);
963 }
964 else
965 {
966 EndpointProperties->Period = ENDPOINT_INTERRUPT_1ms;
967 }
968 }
969
970 if ((DeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB) != 0)
971 {
972 Endpoint->Flags |= ENDPOINT_FLAG_ROOTHUB_EP0;
973 }
974
975 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
976 {
977 IsAllocatedBandwidth = USBPORT_AllocateBandwidthUSB2(FdoDevice, Endpoint);
978 }
979 else
980 {
981 EndpointProperties->UsbBandwidth = USBPORT_CalculateUsbBandwidth(FdoDevice,
982 Endpoint);
983
984 IsAllocatedBandwidth = USBPORT_AllocateBandwidth(FdoDevice, Endpoint);
985 }
986
987 if (!IsAllocatedBandwidth)
988 {
989 Status = USBPORT_USBDStatusToNtStatus(NULL, USBD_STATUS_NO_BANDWIDTH);
990
991 if (UsbdStatus)
992 {
993 *UsbdStatus = USBD_STATUS_NO_BANDWIDTH;
994 }
995
996 goto ExitWithError;
997 }
998
999 Direction = USB_ENDPOINT_DIRECTION_OUT(EndpointDescriptor->bEndpointAddress);
1000 EndpointProperties->Direction = Direction;
1001
1002 if (DeviceHandle->IsRootHub)
1003 {
1004 Endpoint->EndpointWorker = 0; // USBPORT_RootHubEndpointWorker;
1005
1006 Endpoint->Flags |= ENDPOINT_FLAG_ROOTHUB_EP0;
1007
1008 Endpoint->StateLast = USBPORT_ENDPOINT_ACTIVE;
1009 Endpoint->StateNext = USBPORT_ENDPOINT_ACTIVE;
1010
1011 PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
1012
1013 if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
1014 {
1015 PdoExtension->Endpoint = Endpoint;
1016 }
1017
1018 USBDStatus = USBD_STATUS_SUCCESS;
1019 }
1020 else
1021 {
1022 Endpoint->EndpointWorker = 1; // USBPORT_DmaEndpointWorker;
1023
1024 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1025
1026 Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1027 &Endpoint->EndpointProperties,
1028 &EndpointRequirements);
1029
1030 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1031
1032 if ((EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_BULK) ||
1033 (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT))
1034 {
1035 EndpointProperties->MaxTransferSize = EndpointRequirements.MaxTransferSize;
1036 }
1037
1038 if (EndpointRequirements.HeaderBufferSize)
1039 {
1040 HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice,
1041 EndpointRequirements.HeaderBufferSize);
1042 }
1043 else
1044 {
1045 HeaderBuffer = NULL;
1046 }
1047
1048 if (HeaderBuffer || (EndpointRequirements.HeaderBufferSize == 0))
1049 {
1050 Endpoint->HeaderBuffer = HeaderBuffer;
1051
1052 if (HeaderBuffer)
1053 {
1054 EndpointProperties->BufferVA = HeaderBuffer->VirtualAddress;
1055 EndpointProperties->BufferPA = HeaderBuffer->PhysicalAddress;
1056 EndpointProperties->BufferLength = HeaderBuffer->BufferLength; // BufferLength + LengthPadded;
1057 }
1058
1059 MpStatus = MiniportOpenEndpoint(FdoDevice, Endpoint);
1060
1061 Endpoint->Flags |= ENDPOINT_FLAG_DMA_TYPE;
1062 Endpoint->Flags |= ENDPOINT_FLAG_QUEUENE_EMPTY;
1063
1064 if (MpStatus == 0)
1065 {
1066 ULONG State;
1067
1068 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
1069 &Endpoint->EndpointOldIrql);
1070
1071 Endpoint->StateLast = USBPORT_ENDPOINT_PAUSED;
1072 Endpoint->StateNext = USBPORT_ENDPOINT_PAUSED;
1073
1074 USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_ACTIVE);
1075
1076 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
1077 Endpoint->EndpointOldIrql);
1078
1079 while (TRUE)
1080 {
1081 KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
1082 &Endpoint->EndpointOldIrql);
1083
1084 State = USBPORT_GetEndpointState(Endpoint);
1085
1086 KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
1087 Endpoint->EndpointOldIrql);
1088
1089 if (State == USBPORT_ENDPOINT_ACTIVE)
1090 {
1091 break;
1092 }
1093
1094 USBPORT_Wait(FdoDevice, 1); // 1 msec.
1095 }
1096 }
1097 }
1098 else
1099 {
1100 MpStatus = MP_STATUS_NO_RESOURCES;
1101 Endpoint->HeaderBuffer = NULL;
1102 }
1103
1104 if (MpStatus)
1105 {
1106 USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
1107 }
1108 else
1109 {
1110 USBDStatus = USBD_STATUS_SUCCESS;
1111 }
1112 }
1113
1114 if (UsbdStatus)
1115 {
1116 *UsbdStatus = USBDStatus;
1117 }
1118
1119 Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus);
1120
1121 if (NT_SUCCESS(Status))
1122 {
1123 USBPORT_AddPipeHandle(DeviceHandle, PipeHandle);
1124
1125 ExInterlockedInsertTailList(&FdoExtension->EndpointList,
1126 &Endpoint->EndpointLink,
1127 &FdoExtension->EndpointListSpinLock);
1128
1129 PipeHandle->Endpoint = Endpoint;
1130 PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_CLOSED;
1131
1132 return Status;
1133 }
1134
1135 ExitWithError:
1136
1137 if (Endpoint)
1138 {
1139 if (IsAllocatedBandwidth)
1140 {
1141 if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
1142 {
1143 USBPORT_FreeBandwidthUSB2(FdoDevice, Endpoint);
1144 }
1145 else
1146 {
1147 USBPORT_FreeBandwidth(FdoDevice, Endpoint);
1148 }
1149 }
1150
1151 if (Endpoint->TtExtension)
1152 {
1153 KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql);
1154 RemoveEntryList(&Endpoint->TtLink);
1155 KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql);
1156 }
1157
1158 ExFreePoolWithTag(Endpoint, USB_PORT_TAG);
1159 }
1160
1161 DPRINT1("USBPORT_OpenPipe: Status - %lx\n", Status);
1162 return Status;
1163 }
1164
1165 NTSTATUS
1166 NTAPI
1167 USBPORT_ReopenPipe(IN PDEVICE_OBJECT FdoDevice,
1168 IN PUSBPORT_ENDPOINT Endpoint)
1169 {
1170 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1171 PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer;
1172 USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0};
1173 PUSBPORT_REGISTRATION_PACKET Packet;
1174 KIRQL MiniportOldIrql;
1175 NTSTATUS Status;
1176
1177 DPRINT1("USBPORT_ReopenPipe ... \n");
1178
1179 FdoExtension = FdoDevice->DeviceExtension;
1180 Packet = &FdoExtension->MiniPortInterface->Packet;
1181
1182 while (TRUE)
1183 {
1184 if (!InterlockedIncrement(&Endpoint->LockCounter))
1185 break;
1186
1187 InterlockedDecrement(&Endpoint->LockCounter);
1188 USBPORT_Wait(FdoDevice, 1);
1189 }
1190
1191 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1192
1193 Packet->SetEndpointState(FdoExtension->MiniPortExt,
1194 Endpoint + 1,
1195 USBPORT_ENDPOINT_REMOVE);
1196
1197 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1198
1199 USBPORT_Wait(FdoDevice, 2);
1200
1201 MiniportCloseEndpoint(FdoDevice, Endpoint);
1202
1203 RtlZeroMemory(Endpoint + 1,
1204 Packet->MiniPortEndpointSize);
1205
1206 if (Endpoint->HeaderBuffer)
1207 {
1208 USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer);
1209 Endpoint->HeaderBuffer = NULL;
1210 }
1211
1212 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql);
1213
1214 Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1215 &Endpoint->EndpointProperties,
1216 &EndpointRequirements);
1217
1218 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql);
1219
1220 if (EndpointRequirements.HeaderBufferSize)
1221 {
1222 HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice,
1223 EndpointRequirements.HeaderBufferSize);
1224 }
1225 else
1226 {
1227 HeaderBuffer = NULL;
1228 }
1229
1230 if (HeaderBuffer || EndpointRequirements.HeaderBufferSize == 0)
1231 {
1232 Endpoint->HeaderBuffer = HeaderBuffer;
1233 Status = STATUS_SUCCESS;
1234 }
1235 else
1236 {
1237 Endpoint->HeaderBuffer = 0;
1238 Status = STATUS_INSUFFICIENT_RESOURCES;
1239 }
1240
1241 if (Endpoint->HeaderBuffer && HeaderBuffer)
1242 {
1243 Endpoint->EndpointProperties.BufferVA = HeaderBuffer->VirtualAddress;
1244 Endpoint->EndpointProperties.BufferPA = HeaderBuffer->PhysicalAddress;
1245 Endpoint->EndpointProperties.BufferLength = HeaderBuffer->BufferLength;
1246 }
1247
1248 if (NT_SUCCESS(Status))
1249 {
1250 MiniportOpenEndpoint(FdoDevice, Endpoint);
1251
1252 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1253 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1254
1255 if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE)
1256 {
1257 KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1258
1259 Packet->SetEndpointState(FdoExtension->MiniPortExt,
1260 Endpoint + 1,
1261 USBPORT_ENDPOINT_ACTIVE);
1262
1263 KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1264 }
1265
1266 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1267 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1268 }
1269
1270 InterlockedDecrement(&Endpoint->LockCounter);
1271
1272 return Status;
1273 }
1274
1275 VOID
1276 NTAPI
1277 USBPORT_FlushClosedEndpointList(IN PDEVICE_OBJECT FdoDevice)
1278 {
1279 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1280 KIRQL OldIrql;
1281 PLIST_ENTRY ClosedList;
1282 PUSBPORT_ENDPOINT Endpoint;
1283
1284 DPRINT("USBPORT_FlushClosedEndpointList: ... \n");
1285
1286 FdoExtension = FdoDevice->DeviceExtension;
1287
1288 KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1289 ClosedList = &FdoExtension->EndpointClosedList;
1290
1291 while (!IsListEmpty(ClosedList))
1292 {
1293 Endpoint = CONTAINING_RECORD(ClosedList->Flink,
1294 USBPORT_ENDPOINT,
1295 CloseLink);
1296
1297 RemoveHeadList(ClosedList);
1298 Endpoint->CloseLink.Flink = NULL;
1299 Endpoint->CloseLink.Blink = NULL;
1300
1301 KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1302
1303 USBPORT_DeleteEndpoint(FdoDevice, Endpoint);
1304
1305 KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql);
1306 }
1307
1308 KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql);
1309 }
1310
1311 VOID
1312 NTAPI
1313 USBPORT_InvalidateEndpointHandler(IN PDEVICE_OBJECT FdoDevice,
1314 IN PUSBPORT_ENDPOINT Endpoint,
1315 IN ULONG Type)
1316 {
1317 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1318 PUSBPORT_REGISTRATION_PACKET Packet;
1319 PLIST_ENTRY Entry;
1320 PLIST_ENTRY WorkerLink;
1321 PUSBPORT_ENDPOINT endpoint;
1322 KIRQL OldIrql;
1323 BOOLEAN IsAddEntry = FALSE;
1324
1325 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: Endpoint - %p, Type - %x\n",
1326 Endpoint,
1327 Type);
1328
1329 FdoExtension = FdoDevice->DeviceExtension;
1330 Packet = &FdoExtension->MiniPortInterface->Packet;
1331
1332 if (Endpoint)
1333 {
1334 WorkerLink = &Endpoint->WorkerLink;
1335 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1336 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: KeAcquireSpinLock \n");
1337
1338 if ((!WorkerLink->Flink || !WorkerLink->Blink) &&
1339 !(Endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1340 USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_CLOSED)
1341 {
1342 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1343 InsertTailList(&FdoExtension->WorkerList, WorkerLink);
1344 IsAddEntry = TRUE;
1345 }
1346
1347 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1348
1349 if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
1350 Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1351 }
1352 else
1353 {
1354 KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql);
1355
1356 Entry = &FdoExtension->EndpointList;
1357
1358 while (Entry && Entry != &FdoExtension->EndpointList)
1359 {
1360 endpoint = CONTAINING_RECORD(Entry,
1361 USBPORT_ENDPOINT,
1362 EndpointLink);
1363
1364 if (!endpoint->WorkerLink.Flink || !endpoint->WorkerLink.Blink)
1365 {
1366 if (!(endpoint->Flags & ENDPOINT_FLAG_IDLE) &&
1367 !(endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) &&
1368 USBPORT_GetEndpointState(endpoint) != USBPORT_ENDPOINT_CLOSED)
1369 {
1370 DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n");
1371 InsertTailList(&FdoExtension->WorkerList, &endpoint->WorkerLink);
1372 IsAddEntry = TRUE;
1373 }
1374 }
1375
1376 Entry = endpoint->EndpointLink.Flink;
1377 }
1378
1379 KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql);
1380 }
1381
1382 if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)
1383 {
1384 Type = INVALIDATE_ENDPOINT_WORKER_THREAD;
1385 }
1386 else if (IsAddEntry == FALSE && Type == INVALIDATE_ENDPOINT_INT_NEXT_SOF)
1387 {
1388 Type = INVALIDATE_ENDPOINT_ONLY;
1389 }
1390
1391 switch (Type)
1392 {
1393 case INVALIDATE_ENDPOINT_WORKER_THREAD:
1394 USBPORT_SignalWorkerThread(FdoDevice);
1395 break;
1396
1397 case INVALIDATE_ENDPOINT_WORKER_DPC:
1398 KeInsertQueueDpc(&FdoExtension->WorkerRequestDpc, NULL, NULL);
1399 break;
1400
1401 case INVALIDATE_ENDPOINT_INT_NEXT_SOF:
1402 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1403 Packet->InterruptNextSOF(FdoExtension->MiniPortExt);
1404 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1405 break;
1406 }
1407 }
1408
1409 ULONG
1410 NTAPI
1411 USBPORT_DmaEndpointPaused(IN PDEVICE_OBJECT FdoDevice,
1412 IN PUSBPORT_ENDPOINT Endpoint)
1413 {
1414 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1415 PUSBPORT_REGISTRATION_PACKET Packet;
1416 PLIST_ENTRY Entry;
1417 PUSBPORT_TRANSFER Transfer;
1418 PURB Urb;
1419 ULONG Frame;
1420 ULONG CurrentFrame;
1421 ULONG CompletedLen = 0;
1422 KIRQL OldIrql;
1423
1424 DPRINT_CORE("USBPORT_DmaEndpointPaused \n");
1425
1426 FdoExtension = FdoDevice->DeviceExtension;
1427 Packet = &FdoExtension->MiniPortInterface->Packet;
1428
1429 Entry = Endpoint->TransferList.Flink;
1430
1431 if (Entry == &Endpoint->TransferList)
1432 return USBPORT_ENDPOINT_ACTIVE;
1433
1434 while (Entry && Entry != &Endpoint->TransferList)
1435 {
1436 Transfer = CONTAINING_RECORD(Entry,
1437 USBPORT_TRANSFER,
1438 TransferLink);
1439
1440 if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1441 {
1442 if (Transfer->Flags & TRANSFER_FLAG_ISO &&
1443 Transfer->Flags & TRANSFER_FLAG_SUBMITED &&
1444 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1445 {
1446 Urb = Transfer->Urb;
1447
1448 Frame = Urb->UrbIsochronousTransfer.StartFrame +
1449 Urb->UrbIsochronousTransfer.NumberOfPackets;
1450
1451 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1452 CurrentFrame = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt);
1453 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1454
1455 if (Frame + 1 > CurrentFrame)
1456 {
1457 return USBPORT_GetEndpointState(Endpoint);
1458 }
1459 }
1460
1461 if ((Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1462 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1463 {
1464 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1465
1466 Packet->AbortTransfer(FdoExtension->MiniPortExt,
1467 Endpoint + 1,
1468 Transfer->MiniportTransfer,
1469 &CompletedLen);
1470
1471 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1472
1473 if (Transfer->Flags & TRANSFER_FLAG_ISO)
1474 {
1475 DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_FlushIsoTransfer\n");
1476 ASSERT(FALSE); //USBPORT_FlushIsoTransfer();
1477 }
1478 else
1479 {
1480 Transfer->CompletedTransferLen = CompletedLen;
1481 }
1482 }
1483
1484 RemoveEntryList(&Transfer->TransferLink);
1485 Entry = Transfer->TransferLink.Flink;
1486
1487 if (Transfer->Flags & TRANSFER_FLAG_SPLITED)
1488 {
1489 USBPORT_CancelSplitTransfer(Transfer);
1490 }
1491 else
1492 {
1493 InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink);
1494 }
1495 }
1496 else
1497 {
1498 Entry = Transfer->TransferLink.Flink;
1499 }
1500 }
1501
1502 return USBPORT_ENDPOINT_ACTIVE;
1503 }
1504
1505 ULONG
1506 NTAPI
1507 USBPORT_DmaEndpointActive(IN PDEVICE_OBJECT FdoDevice,
1508 IN PUSBPORT_ENDPOINT Endpoint)
1509 {
1510 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1511 PUSBPORT_REGISTRATION_PACKET Packet;
1512 PLIST_ENTRY Entry;
1513 PUSBPORT_TRANSFER Transfer;
1514 LARGE_INTEGER TimeOut;
1515 MPSTATUS MpStatus;
1516 KIRQL OldIrql;
1517
1518 DPRINT_CORE("USBPORT_DmaEndpointActive \n");
1519
1520 FdoExtension = FdoDevice->DeviceExtension;
1521
1522 Entry = Endpoint->TransferList.Flink;
1523
1524 while (Entry && Entry != &Endpoint->TransferList)
1525 {
1526 Transfer = CONTAINING_RECORD(Entry,
1527 USBPORT_TRANSFER,
1528 TransferLink);
1529
1530 if (!(Transfer->Flags & TRANSFER_FLAG_SUBMITED) &&
1531 !(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1532 {
1533 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1534
1535 Packet = &FdoExtension->MiniPortInterface->Packet;
1536
1537 if (Transfer->Flags & TRANSFER_FLAG_ISO)
1538 {
1539 DPRINT1("USBPORT_DmaEndpointActive: FIXME call SubmitIsoTransfer\n");
1540
1541 MpStatus = Packet->SubmitIsoTransfer(FdoExtension->MiniPortExt,
1542 Endpoint + 1,
1543 &Transfer->TransferParameters,
1544 Transfer->MiniportTransfer,
1545 NULL);//&Transfer->IsoTransferParameters);
1546 }
1547 else
1548 {
1549 MpStatus = Packet->SubmitTransfer(FdoExtension->MiniPortExt,
1550 Endpoint + 1,
1551 &Transfer->TransferParameters,
1552 Transfer->MiniportTransfer,
1553 &Transfer->SgList);
1554 }
1555
1556 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
1557
1558 if (MpStatus)
1559 {
1560 if ((MpStatus != MP_STATUS_FAILURE) && Transfer->Flags & TRANSFER_FLAG_ISO)
1561 {
1562 DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_ErrorCompleteIsoTransfer\n");
1563 ASSERT(FALSE); //USBPORT_ErrorCompleteIsoTransfer();
1564 }
1565
1566 return USBPORT_ENDPOINT_ACTIVE;
1567 }
1568
1569 Transfer->Flags |= TRANSFER_FLAG_SUBMITED;
1570 KeQuerySystemTime(&Transfer->Time);
1571
1572 TimeOut.QuadPart = 10000 * Transfer->TimeOut;
1573 Transfer->Time.QuadPart += TimeOut.QuadPart;
1574 }
1575
1576 if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED))
1577 {
1578 return USBPORT_ENDPOINT_PAUSED;
1579 }
1580
1581 Entry = Transfer->TransferLink.Flink;
1582 }
1583
1584 return USBPORT_ENDPOINT_ACTIVE;
1585 }
1586
1587 VOID
1588 NTAPI
1589 USBPORT_DmaEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint)
1590 {
1591 PDEVICE_OBJECT FdoDevice;
1592 ULONG PrevState;
1593 ULONG EndpointState;
1594 BOOLEAN IsPaused = FALSE;
1595
1596 DPRINT_CORE("USBPORT_DmaEndpointWorker ... \n");
1597
1598 FdoDevice = Endpoint->FdoDevice;
1599
1600 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1601
1602 PrevState = USBPORT_GetEndpointState(Endpoint);
1603
1604 if (PrevState == USBPORT_ENDPOINT_PAUSED)
1605 {
1606 EndpointState = USBPORT_DmaEndpointPaused(FdoDevice, Endpoint);
1607 }
1608 else if (PrevState == USBPORT_ENDPOINT_ACTIVE)
1609 {
1610 EndpointState = USBPORT_DmaEndpointActive(FdoDevice, Endpoint);
1611 }
1612 else
1613 {
1614 #ifndef NDEBUG_USBPORT_CORE
1615 DPRINT1("USBPORT_DmaEndpointWorker: DbgBreakPoint. EndpointState - %x\n",
1616 EndpointState);
1617 DbgBreakPoint();
1618 #endif
1619 EndpointState = USBPORT_ENDPOINT_UNKNOWN;
1620 }
1621
1622 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1623
1624 USBPORT_FlushCancelList(Endpoint);
1625
1626 KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
1627
1628 if (EndpointState == PrevState)
1629 {
1630 if (EndpointState == USBPORT_ENDPOINT_PAUSED)
1631 {
1632 IsPaused = TRUE;
1633 }
1634 }
1635 else
1636 {
1637 USBPORT_SetEndpointState(Endpoint, EndpointState);
1638 }
1639
1640 KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
1641
1642 if (IsPaused)
1643 {
1644 USBPORT_InvalidateEndpointHandler(FdoDevice,
1645 Endpoint,
1646 INVALIDATE_ENDPOINT_WORKER_THREAD);
1647 }
1648
1649 DPRINT_CORE("USBPORT_DmaEndpointWorker exit \n");
1650 }
1651
1652 BOOLEAN
1653 NTAPI
1654 USBPORT_EndpointWorker(IN PUSBPORT_ENDPOINT Endpoint,
1655 IN BOOLEAN LockNotChecked)
1656 {
1657 PDEVICE_OBJECT FdoDevice;
1658 PUSBPORT_DEVICE_EXTENSION FdoExtension;
1659 PUSBPORT_REGISTRATION_PACKET Packet;
1660 ULONG EndpointState;
1661
1662 DPRINT_CORE("USBPORT_EndpointWorker: Endpoint - %p, LockNotChecked - %x\n",
1663 Endpoint,
1664 LockNotChecked);
1665
1666 FdoDevice = Endpoint->FdoDevice;
1667 FdoExtension = FdoDevice->DeviceExtension;
1668 Packet = &FdoExtension->MiniPortInterface->Packet;
1669
1670 if (LockNotChecked == FALSE)
1671 {
1672 if (InterlockedIncrement(&Endpoint->LockCounter))
1673 {
1674 InterlockedDecrement(&Endpoint->LockCounter);
1675 DPRINT_CORE("USBPORT_EndpointWorker: LockCounter > 0\n");
1676 return TRUE;
1677 }
1678 }
1679
1680 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1681
1682 KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
1683
1684 if (USBPORT_GetEndpointState(Endpoint) == USBPORT_ENDPOINT_CLOSED)
1685 {
1686 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1687 InterlockedDecrement(&Endpoint->LockCounter);
1688 DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_CLOSED. return FALSE\n");
1689 return FALSE;
1690 }
1691
1692 if ((Endpoint->Flags & (ENDPOINT_FLAG_ROOTHUB_EP0 | ENDPOINT_FLAG_NUKE)) == 0)
1693 {
1694 KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1695 Packet->PollEndpoint(FdoExtension->MiniPortExt, Endpoint + 1);
1696 KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1697 }
1698
1699 EndpointState = USBPORT_GetEndpointState(Endpoint);
1700
1701 if (EndpointState == USBPORT_ENDPOINT_REMOVE)
1702 {
1703 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1704 Endpoint->StateLast = USBPORT_ENDPOINT_CLOSED;
1705 Endpoint->StateNext = USBPORT_ENDPOINT_CLOSED;
1706 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1707
1708 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1709
1710 KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock);
1711
1712 ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
1713 &Endpoint->CloseLink,
1714 &FdoExtension->EndpointClosedSpinLock);
1715
1716 KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock);
1717
1718 InterlockedDecrement(&Endpoint->LockCounter);
1719 DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_REMOVE. return FALSE\n");
1720 return FALSE;
1721 }
1722
1723 if (!IsListEmpty(&Endpoint->PendingTransferList) ||
1724 !IsListEmpty(&Endpoint->TransferList) ||
1725 !IsListEmpty(&Endpoint->CancelList))
1726 {
1727 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1728
1729 EndpointState = USBPORT_GetEndpointState(Endpoint);
1730
1731 KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock);
1732 if (EndpointState == Endpoint->StateNext)
1733 {
1734 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1735
1736 if (Endpoint->EndpointWorker)
1737 {
1738 USBPORT_DmaEndpointWorker(Endpoint);
1739 }
1740 else
1741 {
1742 USBPORT_RootHubEndpointWorker(Endpoint);
1743 }
1744
1745 USBPORT_FlushAbortList(Endpoint);
1746
1747 InterlockedDecrement(&Endpoint->LockCounter);
1748 DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1749 return FALSE;
1750 }
1751
1752 KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock);
1753 InterlockedDecrement(&Endpoint->LockCounter);
1754
1755 DPRINT_CORE("USBPORT_EndpointWorker: return TRUE\n");
1756 return TRUE;
1757 }
1758
1759 KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
1760
1761 USBPORT_FlushAbortList(Endpoint);
1762
1763 InterlockedDecrement(&Endpoint->LockCounter);
1764 DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n");
1765 return FALSE;
1766 }