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