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