ab60b451739330f380b332c53d696a5f96699a2a
[reactos.git] / drivers / usb / usbhub_new / usbhub.c
1 /*
2 * PROJECT: ReactOS USB Hub Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: USBHub main driver functions
5 * COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6 */
7
8 #include "usbhub.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define NDEBUG_USBHUB_SCE
14 #define NDEBUG_USBHUB_PNP
15 #include "dbg_uhub.h"
16
17 #include <ntddstor.h>
18
19 PWSTR GenericUSBDeviceString = NULL;
20
21 NTSTATUS
22 NTAPI
23 USBH_Wait(IN ULONG Milliseconds)
24 {
25 LARGE_INTEGER Interval;
26
27 DPRINT("USBH_Wait: Milliseconds - %x\n", Milliseconds);
28 Interval.QuadPart = -10000LL * Milliseconds - ((ULONGLONG)KeQueryTimeIncrement() - 1);
29 return KeDelayExecutionThread(KernelMode, FALSE, &Interval);
30 }
31
32 NTSTATUS
33 NTAPI
34 USBH_GetConfigValue(IN PWSTR ValueName,
35 IN ULONG ValueType,
36 IN PVOID ValueData,
37 IN ULONG ValueLength,
38 IN PVOID Context,
39 IN PVOID EntryContext)
40 {
41 NTSTATUS Status = STATUS_SUCCESS;
42
43 DPRINT("USBHUB_GetConfigValue: ... \n");
44
45 if (ValueType == REG_BINARY)
46 {
47 *(PUCHAR)EntryContext = *(PUCHAR)ValueData;
48 }
49 else if (ValueType == REG_DWORD)
50 {
51 *(PULONG)EntryContext = *(PULONG)ValueData;
52 }
53 else
54 {
55 Status = STATUS_INVALID_PARAMETER;
56 }
57
58 return Status;
59 }
60
61 VOID
62 NTAPI
63 USBH_CompleteIrp(IN PIRP Irp,
64 IN NTSTATUS CompleteStatus)
65 {
66 if (CompleteStatus != STATUS_SUCCESS)
67 {
68 DPRINT1("USBH_CompleteIrp: Irp - %p, CompleteStatus - %X\n",
69 Irp,
70 CompleteStatus);
71 }
72
73 Irp->IoStatus.Status = CompleteStatus;
74 IoCompleteRequest(Irp, IO_NO_INCREMENT);
75 }
76
77 NTSTATUS
78 NTAPI
79 USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject,
80 IN PIRP Irp)
81 {
82 DPRINT_PNP("USBH_PassIrp: DeviceObject - %p, Irp - %p\n",
83 DeviceObject,
84 Irp);
85
86 IoSkipCurrentIrpStackLocation(Irp);
87 return IoCallDriver(DeviceObject, Irp);
88 }
89
90 NTSTATUS
91 NTAPI
92 USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject,
93 IN PIRP Irp,
94 IN PVOID Context)
95 {
96 PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
97 KIRQL OldIrql;
98 BOOLEAN TimerCancelled;
99
100 DPRINT("USBH_SyncIrpComplete: ... \n");
101
102 HubTimeoutContext = Context;
103
104 KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
105 HubTimeoutContext->IsNormalCompleted = TRUE;
106 TimerCancelled = KeCancelTimer(&HubTimeoutContext->UrbTimeoutTimer);
107 KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
108
109 if (TimerCancelled)
110 {
111 KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
112 EVENT_INCREMENT,
113 FALSE);
114 }
115
116 return STATUS_SUCCESS;
117 }
118
119 BOOLEAN
120 NTAPI
121 IsBitSet(IN PUCHAR BitMapAddress,
122 IN USHORT Bit)
123 {
124 BOOLEAN IsSet;
125
126 IsSet = (BitMapAddress[Bit / 8] & (1 << (Bit & 7))) != 0;
127 DPRINT("IsBitSet: Bit - %lX, IsSet - %x\n", Bit, IsSet);
128 return IsSet;
129 }
130
131 PUSBHUB_PORT_PDO_EXTENSION
132 NTAPI
133 PdoExt(IN PDEVICE_OBJECT DeviceObject)
134 {
135 PVOID PdoExtension;
136
137 DPRINT("PdoExt: DeviceObject - %p\n", DeviceObject);
138
139 if (DeviceObject)
140 {
141 PdoExtension = DeviceObject->DeviceExtension;
142 }
143 else
144 {
145 PdoExtension = NULL;
146 }
147
148 return (PUSBHUB_PORT_PDO_EXTENSION)PdoExtension;
149 }
150
151 NTSTATUS
152 NTAPI
153 USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject,
154 IN ULONG FailReason)
155 {
156 NTSTATUS Status;
157 HANDLE KeyHandle;
158 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FailReasonID");
159
160 DPRINT("USBH_WriteFailReason: ID - %x\n", FailReason);
161
162 Status = IoOpenDeviceRegistryKey(DeviceObject,
163 PLUGPLAY_REGKEY_DEVICE,
164 STANDARD_RIGHTS_ALL,
165 &KeyHandle);
166
167 if (NT_SUCCESS(Status))
168 {
169 ZwSetValueKey(KeyHandle,
170 &ValueName,
171 0,
172 REG_DWORD,
173 &FailReason,
174 sizeof(FailReason));
175
176 ZwClose(KeyHandle);
177 }
178
179 return Status;
180 }
181
182 VOID
183 NTAPI
184 USBH_UrbTimeoutDPC(IN PKDPC Dpc,
185 IN PVOID DeferredContext,
186 IN PVOID SystemArgument1,
187 IN PVOID SystemArgument2)
188 {
189 PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
190 KIRQL OldIrql;
191 BOOL IsCompleted;
192
193 DPRINT("USBH_TimeoutDPC ... \n");
194
195 HubTimeoutContext = DeferredContext;
196
197 KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
198 IsCompleted = HubTimeoutContext->IsNormalCompleted;
199 KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
200
201 if (!IsCompleted)
202 {
203 IoCancelIrp(HubTimeoutContext->Irp);
204 }
205
206 KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
207 EVENT_INCREMENT,
208 FALSE);
209 }
210
211 NTSTATUS
212 NTAPI
213 USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject,
214 IN PCWSTR ValueName,
215 IN PVOID Data,
216 IN ULONG DataSize,
217 IN ULONG Type,
218 IN ULONG DevInstKeyType)
219 {
220 NTSTATUS Status;
221 UNICODE_STRING ValueNameString;
222 HANDLE KeyHandle;
223
224 DPRINT("USBH_SetPdoRegistryParameter ... \n");
225
226 RtlInitUnicodeString(&ValueNameString, ValueName);
227
228 Status = IoOpenDeviceRegistryKey(DeviceObject,
229 DevInstKeyType,
230 STANDARD_RIGHTS_ALL,
231 &KeyHandle);
232
233 if (NT_SUCCESS(Status))
234 {
235 ZwSetValueKey(KeyHandle,
236 &ValueNameString,
237 0,
238 Type,
239 Data,
240 DataSize);
241
242 ZwClose(KeyHandle);
243 }
244
245 return Status;
246 }
247
248 NTSTATUS
249 NTAPI
250 USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject,
251 IN PURB Urb)
252 {
253 KEVENT Event;
254 IO_STATUS_BLOCK IoStatusBlock;
255 PIRP Irp;
256 PIO_STACK_LOCATION IoStack;
257 PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
258 BOOLEAN IsWaitTimeout = FALSE;
259 LARGE_INTEGER DueTime;
260 NTSTATUS Status;
261
262 DPRINT("USBH_SyncSubmitUrb: ... \n");
263
264 Urb->UrbHeader.UsbdDeviceHandle = NULL;
265
266 KeInitializeEvent(&Event, NotificationEvent, FALSE);
267
268 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
269 DeviceObject,
270 NULL,
271 0,
272 NULL,
273 0,
274 TRUE,
275 &Event,
276 &IoStatusBlock);
277
278 if (!Irp)
279 {
280 return STATUS_INSUFFICIENT_RESOURCES;
281 }
282
283 IoStack = IoGetNextIrpStackLocation(Irp);
284 IoStack->Parameters.Others.Argument1 = Urb;
285
286 HubTimeoutContext = ExAllocatePoolWithTag(NonPagedPool,
287 sizeof(USBHUB_URB_TIMEOUT_CONTEXT),
288 USB_HUB_TAG);
289
290 if (HubTimeoutContext)
291 {
292 RtlZeroMemory(HubTimeoutContext, sizeof(USBHUB_URB_TIMEOUT_CONTEXT));
293
294 HubTimeoutContext->Irp = Irp;
295 HubTimeoutContext->IsNormalCompleted = FALSE;
296
297 KeInitializeEvent(&HubTimeoutContext->UrbTimeoutEvent,
298 NotificationEvent,
299 FALSE);
300
301 KeInitializeSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock);
302 KeInitializeTimer(&HubTimeoutContext->UrbTimeoutTimer);
303
304 KeInitializeDpc(&HubTimeoutContext->UrbTimeoutDPC,
305 USBH_UrbTimeoutDPC,
306 HubTimeoutContext);
307
308 DueTime.QuadPart = -5000 * 10000; // Timeout 5 sec.
309
310 KeSetTimer(&HubTimeoutContext->UrbTimeoutTimer,
311 DueTime,
312 &HubTimeoutContext->UrbTimeoutDPC);
313
314 IoSetCompletionRoutine(Irp,
315 USBH_SyncIrpComplete,
316 HubTimeoutContext,
317 TRUE,
318 TRUE,
319 TRUE);
320
321 IsWaitTimeout = TRUE;
322 }
323
324 Status = IoCallDriver(DeviceObject, Irp);
325
326 if (Status == STATUS_PENDING)
327 {
328 KeWaitForSingleObject(&Event,
329 Suspended,
330 KernelMode,
331 FALSE,
332 NULL);
333 }
334 else
335 {
336 IoStatusBlock.Status = Status;
337 }
338
339 if (IsWaitTimeout)
340 {
341 KeWaitForSingleObject(&HubTimeoutContext->UrbTimeoutEvent,
342 Suspended,
343 KernelMode,
344 FALSE,
345 NULL);
346
347 ExFreePoolWithTag(HubTimeoutContext, USB_HUB_TAG);
348 }
349
350 return IoStatusBlock.Status;
351 }
352
353 NTSTATUS
354 NTAPI
355 USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice,
356 IN PURB Urb)
357 {
358 PUSBHUB_FDO_EXTENSION HubExtension;
359
360 DPRINT("USBH_FdoSyncSubmitUrb: FdoDevice - %p, Urb - %p\n",
361 FdoDevice,
362 Urb);
363
364 HubExtension = FdoDevice->DeviceExtension;
365 return USBH_SyncSubmitUrb(HubExtension->LowerDevice, Urb);
366 }
367
368 NTSTATUS
369 NTAPI
370 USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension,
371 IN PVOID TransferBuffer,
372 IN ULONG BufferLen,
373 IN BOOLEAN IsDeviceToHost,
374 IN USHORT Function,
375 IN BM_REQUEST_TYPE RequestType,
376 IN UCHAR Request,
377 IN USHORT RequestValue,
378 IN USHORT RequestIndex)
379 {
380 struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb;
381 ULONG TransferFlags;
382 PVOID Buffer = NULL;
383 ULONG Length;
384 NTSTATUS Status;
385
386 DPRINT("USBH_Transact: ... \n");
387
388 if (BufferLen)
389 {
390 Length = ALIGN_DOWN_BY(BufferLen + sizeof(ULONG), sizeof(ULONG));
391
392 Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
393
394 if (!Buffer)
395 {
396 return STATUS_INSUFFICIENT_RESOURCES;
397 }
398
399 RtlZeroMemory(Buffer, Length);
400 }
401
402 Urb = ExAllocatePoolWithTag(NonPagedPool,
403 sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
404 USB_HUB_TAG);
405
406 if (!Urb)
407 {
408 if (Buffer)
409 {
410 ExFreePoolWithTag(Buffer, USB_HUB_TAG);
411 }
412
413 return STATUS_INSUFFICIENT_RESOURCES;
414 }
415
416 RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
417
418 if (IsDeviceToHost)
419 {
420 if (BufferLen)
421 {
422 RtlZeroMemory(TransferBuffer, BufferLen);
423 }
424
425 TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
426 }
427 else
428 {
429 if (BufferLen)
430 {
431 RtlCopyMemory(Buffer, TransferBuffer, BufferLen);
432 }
433
434 TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
435 }
436
437 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
438 Urb->Hdr.Function = Function;
439 Urb->Hdr.UsbdDeviceHandle = NULL;
440
441 Urb->TransferFlags = TransferFlags;
442 Urb->TransferBuffer = BufferLen != 0 ? Buffer : NULL;
443 Urb->TransferBufferLength = BufferLen;
444 Urb->TransferBufferMDL = NULL;
445 Urb->UrbLink = NULL;
446
447 Urb->RequestTypeReservedBits = RequestType.B;
448 Urb->Request = Request;
449 Urb->Value = RequestValue;
450 Urb->Index = RequestIndex;
451
452 Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, (PURB)Urb);
453
454 if (IsDeviceToHost && BufferLen)
455 {
456 RtlCopyMemory(TransferBuffer, Buffer, BufferLen);
457 }
458
459 if (Buffer)
460 {
461 ExFreePoolWithTag(Buffer, USB_HUB_TAG);
462 }
463
464 ExFreePoolWithTag(Urb, USB_HUB_TAG);
465
466 return Status;
467 }
468
469 NTSTATUS
470 NTAPI
471 USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
472 IN USHORT Port)
473 {
474 USB_PORT_STATUS_AND_CHANGE PortStatus;
475 KEVENT Event;
476 LARGE_INTEGER Timeout;
477 ULONG ResetRetry = 0;
478 NTSTATUS Status;
479
480 DPRINT("USBH_SyncResetPort: Port - %x\n", Port);
481
482 InterlockedIncrement(&HubExtension->PendingRequestCount);
483
484 KeWaitForSingleObject(&HubExtension->HubPortSemaphore,
485 Executive,
486 KernelMode,
487 FALSE,
488 NULL);
489
490 Status = USBH_SyncGetPortStatus(HubExtension,
491 Port,
492 &PortStatus,
493 sizeof(USB_PORT_STATUS_AND_CHANGE));
494
495 if (NT_SUCCESS(Status) &&
496 (PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0))
497 {
498 Status = STATUS_UNSUCCESSFUL;
499 goto Exit;
500 }
501
502 HubExtension->HubFlags |= USBHUB_FDO_FLAG_RESET_PORT_LOCK;
503
504 while (TRUE)
505 {
506 BM_REQUEST_TYPE RequestType;
507
508 KeInitializeEvent(&Event, NotificationEvent, FALSE);
509
510 InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
511 &Event);
512
513 RequestType.B = 0;
514 RequestType.Recipient = BMREQUEST_TO_DEVICE;
515 RequestType.Type = BMREQUEST_CLASS;
516 RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
517
518 Status = USBH_Transact(HubExtension,
519 NULL,
520 0,
521 BMREQUEST_HOST_TO_DEVICE,
522 URB_FUNCTION_CLASS_OTHER,
523 RequestType,
524 USB_REQUEST_SET_FEATURE,
525 USBHUB_FEATURE_PORT_RESET,
526 Port);
527
528 Timeout.QuadPart = -5000 * 10000;
529
530 if (!NT_SUCCESS(Status))
531 {
532 InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
533 NULL);
534
535 USBH_Wait(10);
536 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
537
538 goto Exit;
539 }
540
541 Status = KeWaitForSingleObject(&Event,
542 Suspended,
543 KernelMode,
544 FALSE,
545 &Timeout);
546
547 if (Status != STATUS_TIMEOUT)
548 {
549 break;
550 }
551
552 Status = USBH_SyncGetPortStatus(HubExtension,
553 Port,
554 &PortStatus,
555 sizeof(USB_PORT_STATUS_AND_CHANGE));
556
557 if (!NT_SUCCESS(Status) ||
558 (PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0) ||
559 ResetRetry >= USBHUB_RESET_PORT_MAX_RETRY)
560 {
561 InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
562 NULL);
563
564 USBH_Wait(10);
565 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
566
567 Status = STATUS_DEVICE_DATA_ERROR;
568 goto Exit;
569 }
570
571 ResetRetry++;
572 }
573
574 Status = USBH_SyncGetPortStatus(HubExtension,
575 Port,
576 &PortStatus,
577 sizeof(USB_PORT_STATUS_AND_CHANGE));
578
579 if ((PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus == 0) &&
580 NT_SUCCESS(Status) &&
581 HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
582 {
583 Status = STATUS_DEVICE_DATA_ERROR;
584 }
585
586 USBH_Wait(10);
587 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
588
589 Exit:
590
591 KeReleaseSemaphore(&HubExtension->HubPortSemaphore,
592 LOW_REALTIME_PRIORITY,
593 1,
594 FALSE);
595
596 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
597 {
598 KeSetEvent(&HubExtension->PendingRequestEvent,
599 EVENT_INCREMENT,
600 FALSE);
601 }
602
603 return Status;
604 }
605
606 NTSTATUS
607 NTAPI
608 USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension,
609 IN PUSB_DEVICE_HANDLE DeviceHandle,
610 OUT USB_DEVICE_TYPE * OutDeviceType)
611 {
612 PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
613 PUSB_DEVICE_INFORMATION_0 DeviceInfo;
614 SIZE_T DeviceInformationBufferLength;
615 USB_DEVICE_TYPE DeviceType = Usb11Device;
616 ULONG dummy;
617 NTSTATUS Status;
618
619 DPRINT("USBH_GetDeviceType: ... \n");
620
621 QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
622
623 if (!QueryDeviceInformation)
624 {
625 DPRINT1("USBH_GetDeviceType: no QueryDeviceInformation()\n");
626 return STATUS_NOT_IMPLEMENTED;
627 }
628
629 DeviceInformationBufferLength = sizeof(USB_DEVICE_INFORMATION_0);
630
631 while (TRUE)
632 {
633 DeviceInfo = ExAllocatePoolWithTag(PagedPool,
634 DeviceInformationBufferLength,
635 USB_HUB_TAG);
636
637 if (!DeviceInfo)
638 {
639 DPRINT1("USBH_GetDeviceType: ExAllocatePoolWithTag() failed\n");
640 Status = STATUS_INSUFFICIENT_RESOURCES;
641 break;
642 }
643
644 RtlZeroMemory(DeviceInfo, DeviceInformationBufferLength);
645
646 DeviceInfo->InformationLevel = 0;
647
648 Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
649 DeviceHandle,
650 DeviceInfo,
651 DeviceInformationBufferLength,
652 &dummy);
653
654 if (Status != STATUS_BUFFER_TOO_SMALL)
655 {
656 if (NT_SUCCESS(Status))
657 {
658 DeviceType = DeviceInfo->DeviceType;
659 }
660
661 ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
662 break;
663 }
664
665 DeviceInformationBufferLength = DeviceInfo->ActualLength;
666 ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
667 }
668
669 if (OutDeviceType)
670 {
671 *OutDeviceType = DeviceType;
672 DPRINT("USBH_GetDeviceType: DeviceType - %x\n", DeviceType);
673 }
674
675 return Status;
676 }
677
678 NTSTATUS
679 NTAPI
680 USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension,
681 IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer)
682 {
683 PUSB_BUSIFFN_GET_EXTENDED_HUB_INFO GetExtendedHubInformation;
684 ULONG dummy = 0;
685
686 DPRINT("USBHUB_GetExtendedHubInfo: ... \n");
687
688 GetExtendedHubInformation = HubExtension->BusInterface.GetExtendedHubInformation;
689
690 return GetExtendedHubInformation(HubExtension->BusInterface.BusContext,
691 HubExtension->LowerPDO,
692 HubInfoBuffer,
693 sizeof(USB_EXTHUB_INFORMATION_0),
694 &dummy);
695 }
696
697 PUSBHUB_FDO_EXTENSION
698 NTAPI
699 USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension)
700 {
701 PDEVICE_OBJECT Device;
702 PUSBHUB_FDO_EXTENSION RootHubExtension;
703
704 DPRINT("USBH_GetRootHubExtension: HubExtension - %p\n", HubExtension);
705
706 RootHubExtension = HubExtension;
707
708 if (HubExtension->LowerPDO != HubExtension->RootHubPdo)
709 {
710 Device = HubExtension->RootHubPdo;
711
712 do
713 {
714 Device = Device->AttachedDevice;
715 }
716 while (Device->DriverObject != HubExtension->Common.SelfDevice->DriverObject);
717
718 RootHubExtension = Device->DeviceExtension;
719 }
720
721 DPRINT("USBH_GetRootHubExtension: RootHubExtension - %p\n", RootHubExtension);
722
723 return RootHubExtension;
724 }
725
726 NTSTATUS
727 NTAPI
728 USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject,
729 IN OUT PDEVICE_OBJECT * OutPdo1,
730 IN OUT PDEVICE_OBJECT * OutPdo2)
731 {
732 KEVENT Event;
733 IO_STATUS_BLOCK IoStatusBlock;
734 PIRP Irp;
735 PIO_STACK_LOCATION IoStack;
736 NTSTATUS Status;
737
738 DPRINT("USBH_SyncGetRootHubPdo: ... \n");
739
740 KeInitializeEvent(&Event, NotificationEvent, FALSE);
741
742 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
743 DeviceObject,
744 NULL,
745 0,
746 NULL,
747 0,
748 TRUE,
749 &Event,
750 &IoStatusBlock);
751
752 if (!Irp)
753 {
754 return STATUS_INSUFFICIENT_RESOURCES;
755 }
756
757 IoStack = IoGetNextIrpStackLocation(Irp);
758 IoStack->Parameters.Others.Argument1 = OutPdo1;
759 IoStack->Parameters.Others.Argument2 = OutPdo2;
760
761 Status = IoCallDriver(DeviceObject, Irp);
762
763 if (Status == STATUS_PENDING)
764 {
765 KeWaitForSingleObject(&Event,
766 Suspended,
767 KernelMode,
768 FALSE,
769 NULL);
770 }
771 else
772 {
773 IoStatusBlock.Status = Status;
774 }
775
776 return IoStatusBlock.Status;
777 }
778
779 NTSTATUS
780 NTAPI
781 USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject,
782 IN OUT PULONG OutHubCount)
783 {
784 KEVENT Event;
785 IO_STATUS_BLOCK IoStatusBlock;
786 PIRP Irp;
787 PIO_STACK_LOCATION IoStack;
788 NTSTATUS Status;
789
790 DPRINT("USBH_SyncGetHubCount: *OutHubCount - %x\n", *OutHubCount);
791
792 KeInitializeEvent(&Event, NotificationEvent, FALSE);
793
794 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_HUB_COUNT,
795 DeviceObject,
796 NULL,
797 0,
798 NULL,
799 0,
800 TRUE,
801 &Event,
802 &IoStatusBlock);
803
804 if (!Irp)
805 {
806 return STATUS_INSUFFICIENT_RESOURCES;
807 }
808
809 IoStack = IoGetNextIrpStackLocation(Irp);
810 IoStack->Parameters.Others.Argument1 = OutHubCount;
811
812 Status = IoCallDriver(DeviceObject, Irp);
813
814 if (Status == STATUS_PENDING)
815 {
816 KeWaitForSingleObject(&Event,
817 Suspended,
818 KernelMode,
819 FALSE,
820 NULL);
821 }
822 else
823 {
824 IoStatusBlock.Status = Status;
825 }
826
827 return IoStatusBlock.Status;
828 }
829
830 PUSB_DEVICE_HANDLE
831 NTAPI
832 USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject)
833 {
834 PIRP Irp;
835 KEVENT Event;
836 IO_STATUS_BLOCK IoStatusBlock;
837 PUSB_DEVICE_HANDLE DeviceHandle = NULL;
838 PIO_STACK_LOCATION IoStack;
839
840 DPRINT("USBH_SyncGetDeviceHandle: ... \n");
841
842 KeInitializeEvent(&Event, NotificationEvent, FALSE);
843
844 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
845 DeviceObject,
846 NULL,
847 0,
848 NULL,
849 0,
850 TRUE,
851 &Event,
852 &IoStatusBlock);
853
854 if (!Irp)
855 {
856 DPRINT1("USBH_SyncGetDeviceHandle: Irp - NULL!\n");
857 return NULL;
858 }
859
860 IoStack = IoGetNextIrpStackLocation(Irp);
861 IoStack->Parameters.Others.Argument1 = &DeviceHandle;
862
863 if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
864 {
865 KeWaitForSingleObject(&Event,
866 Suspended,
867 KernelMode,
868 FALSE,
869 NULL);
870 }
871
872 return DeviceHandle;
873 }
874
875 NTSTATUS
876 NTAPI
877 USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject,
878 IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor)
879 {
880 struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
881 NTSTATUS Status;
882
883 DPRINT("USBH_GetDeviceDescriptor: ... \n");
884
885 Urb = ExAllocatePoolWithTag(NonPagedPool,
886 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
887 USB_HUB_TAG);
888
889 if (!Urb)
890 {
891 DPRINT1("USBH_SyncGetDeviceHandle: Urb - NULL!\n");
892 return STATUS_INSUFFICIENT_RESOURCES;
893 }
894
895 RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
896
897 Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
898 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
899
900 Urb->TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
901 Urb->TransferBuffer = HubDeviceDescriptor;
902 Urb->DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
903
904 Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
905
906 ExFreePoolWithTag(Urb, USB_HUB_TAG);
907
908 return Status;
909 }
910
911 NTSTATUS
912 NTAPI
913 USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
914 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
915 IN ULONG NumberOfBytes,
916 IN PULONG OutLength)
917 {
918 PCOMMON_DEVICE_EXTENSION DeviceExtension;
919 struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
920 NTSTATUS Status;
921
922 DPRINT("USBH_SyncGetDeviceConfigurationDescriptor: ... \n");
923
924 DeviceExtension = DeviceObject->DeviceExtension;
925
926 if (OutLength)
927 {
928 *OutLength = 0;
929 }
930
931 Urb = ExAllocatePoolWithTag(NonPagedPool,
932 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
933 USB_HUB_TAG);
934
935 if (!Urb)
936 {
937 return STATUS_INSUFFICIENT_RESOURCES;
938 }
939
940 RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
941
942 Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
943 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
944
945 Urb->TransferBufferLength = NumberOfBytes;
946 Urb->TransferBuffer = ConfigDescriptor;
947 Urb->DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
948
949 if (DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_HUB ||
950 DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_PARENT)
951 {
952 Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
953 }
954 else
955 {
956 Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
957 }
958
959 if (OutLength)
960 {
961 *OutLength = Urb->TransferBufferLength;
962 }
963
964 if (Urb)
965 {
966 ExFreePoolWithTag(Urb, USB_HUB_TAG);
967 }
968
969 return Status;
970 }
971
972 NTSTATUS
973 NTAPI
974 USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
975 IN PUSB_CONFIGURATION_DESCRIPTOR * OutDescriptor)
976 {
977 PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
978 ULONG ReturnedLen;
979 SIZE_T DescriptorLen;
980 NTSTATUS Status;
981
982 DPRINT("USBH_GetConfigurationDescriptor: ... \n");
983
984 DescriptorLen = MAXUCHAR;
985
986 while (TRUE)
987 {
988 ConfigDescriptor = ExAllocatePoolWithTag(NonPagedPool,
989 DescriptorLen,
990 USB_HUB_TAG);
991
992 if (!ConfigDescriptor)
993 {
994 Status = STATUS_INSUFFICIENT_RESOURCES;
995 break;
996 }
997
998 Status = USBH_SyncGetDeviceConfigurationDescriptor(DeviceObject,
999 ConfigDescriptor,
1000 DescriptorLen,
1001 &ReturnedLen);
1002
1003 if (ReturnedLen < sizeof(USB_CONFIGURATION_DESCRIPTOR))
1004 {
1005 Status = STATUS_DEVICE_DATA_ERROR;
1006 }
1007
1008 if (!NT_SUCCESS(Status))
1009 {
1010 break;
1011 }
1012
1013 *OutDescriptor = ConfigDescriptor;
1014
1015 if (ConfigDescriptor->wTotalLength <= DescriptorLen)
1016 {
1017 break;
1018 }
1019
1020 DescriptorLen = ConfigDescriptor->wTotalLength;
1021
1022 ExFreePool(ConfigDescriptor);
1023 *OutDescriptor = NULL;
1024 }
1025
1026 if (NT_SUCCESS(Status))
1027 {
1028 if (ReturnedLen < ConfigDescriptor->wTotalLength)
1029 {
1030 Status = STATUS_DEVICE_DATA_ERROR;
1031 }
1032 }
1033 else
1034 {
1035 if (ConfigDescriptor)
1036 {
1037 ExFreePool(ConfigDescriptor);
1038 }
1039
1040 *OutDescriptor = NULL;
1041 }
1042
1043 return Status;
1044 }
1045
1046 NTSTATUS
1047 NTAPI
1048 USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension)
1049 {
1050 PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo;
1051 ULONG NumberPorts;
1052 PUSBHUB_PORT_DATA PortData;
1053 USHORT RequestValue;
1054 ULONG NumberOfBytes;
1055 NTSTATUS Status;
1056 PUSB_HUB_DESCRIPTOR HubDescriptor = NULL;
1057 ULONG ix;
1058 ULONG Retry;
1059
1060 DPRINT("USBH_SyncGetHubDescriptor: ... \n");
1061
1062 ExtendedHubInfo = ExAllocatePoolWithTag(NonPagedPool,
1063 sizeof(USB_EXTHUB_INFORMATION_0),
1064 USB_HUB_TAG);
1065
1066 if (!ExtendedHubInfo)
1067 {
1068 Status = STATUS_INSUFFICIENT_RESOURCES;
1069 goto ErrorExit;
1070 }
1071
1072 RtlZeroMemory(ExtendedHubInfo, sizeof(USB_EXTHUB_INFORMATION_0));
1073
1074 Status = USBHUB_GetExtendedHubInfo(HubExtension, ExtendedHubInfo);
1075
1076 if (!NT_SUCCESS(Status))
1077 {
1078 ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
1079 ExtendedHubInfo = NULL;
1080 }
1081
1082 NumberOfBytes = sizeof(USB_HUB_DESCRIPTOR);
1083
1084 HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
1085 NumberOfBytes,
1086 USB_HUB_TAG);
1087
1088 if (!HubDescriptor)
1089 {
1090 Status = STATUS_INSUFFICIENT_RESOURCES;
1091 goto ErrorExit;
1092 }
1093
1094 RtlZeroMemory(HubDescriptor, NumberOfBytes);
1095
1096 RequestValue = 0;
1097 Retry = 0;
1098
1099 while (TRUE)
1100 {
1101 while (Retry <= 5)
1102 {
1103 BM_REQUEST_TYPE RequestType;
1104
1105 RequestType.B = 0;
1106 RequestType.Recipient = BMREQUEST_TO_DEVICE;
1107 RequestType.Type = BMREQUEST_STANDARD;
1108 RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1109
1110 Status = USBH_Transact(HubExtension,
1111 HubDescriptor,
1112 NumberOfBytes,
1113 BMREQUEST_DEVICE_TO_HOST,
1114 URB_FUNCTION_CLASS_DEVICE,
1115 RequestType,
1116 USB_REQUEST_GET_DESCRIPTOR,
1117 RequestValue,
1118 0);
1119
1120 if (NT_SUCCESS(Status))
1121 {
1122 break;
1123 }
1124
1125 RequestValue = 0x2900; // Hub DescriptorType - 0x29
1126
1127 Retry++;
1128 }
1129
1130 if (HubDescriptor->bDescriptorLength <= NumberOfBytes)
1131 {
1132 break;
1133 }
1134
1135 NumberOfBytes = HubDescriptor->bDescriptorLength;
1136 ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
1137
1138 if (Retry >= 5)
1139 {
1140 Status = STATUS_DEVICE_DATA_ERROR;
1141 HubDescriptor = NULL;
1142 goto ErrorExit;
1143 }
1144
1145 HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
1146 NumberOfBytes,
1147 USB_HUB_TAG);
1148
1149 if (!HubDescriptor)
1150 {
1151 Status = STATUS_INSUFFICIENT_RESOURCES;
1152 goto ErrorExit;
1153 }
1154
1155 RtlZeroMemory(HubDescriptor, NumberOfBytes);
1156 }
1157
1158 NumberPorts = HubDescriptor->bNumberOfPorts;
1159
1160 if (HubExtension->PortData)
1161 {
1162 PortData = HubExtension->PortData;
1163
1164 for (ix = 0; ix < NumberPorts; ix++)
1165 {
1166 PortData[ix].PortStatus.AsUlong32 = 0;
1167
1168 if (ExtendedHubInfo)
1169 {
1170 PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
1171 }
1172 else
1173 {
1174 PortData[ix].PortAttributes = 0;
1175 }
1176
1177 PortData[ix].ConnectionStatus = NoDeviceConnected;
1178
1179 if (PortData[ix].DeviceObject != NULL)
1180 {
1181 PortData[ix].ConnectionStatus = DeviceConnected;
1182 }
1183 }
1184 }
1185 else
1186 {
1187 PortData = NULL;
1188
1189 if (HubDescriptor->bNumberOfPorts)
1190 {
1191 PortData = ExAllocatePoolWithTag(NonPagedPool,
1192 NumberPorts * sizeof(USBHUB_PORT_DATA),
1193 USB_HUB_TAG);
1194 }
1195
1196 if (!PortData)
1197 {
1198 Status = STATUS_INSUFFICIENT_RESOURCES;
1199 goto ErrorExit;
1200 }
1201
1202 RtlZeroMemory(PortData, NumberPorts * sizeof(USBHUB_PORT_DATA));
1203
1204 for (ix = 0; ix < NumberPorts; ix++)
1205 {
1206 PortData[ix].ConnectionStatus = NoDeviceConnected;
1207
1208 if (ExtendedHubInfo)
1209 {
1210 PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
1211 }
1212 }
1213 }
1214
1215 if (!NT_SUCCESS(Status))
1216 {
1217 goto ErrorExit;
1218 }
1219
1220 HubExtension->HubDescriptor = HubDescriptor;
1221
1222 HubExtension->PortData = PortData;
1223
1224 if (ExtendedHubInfo)
1225 {
1226 ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
1227 }
1228
1229 return Status;
1230
1231 ErrorExit:
1232
1233 if (HubDescriptor)
1234 {
1235 ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
1236 }
1237
1238 if (ExtendedHubInfo)
1239 {
1240 ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
1241 }
1242
1243 return Status;
1244 }
1245
1246 NTSTATUS
1247 NTAPI
1248 USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject,
1249 IN UCHAR Index,
1250 IN USHORT LanguageId,
1251 IN PUSB_STRING_DESCRIPTOR Descriptor,
1252 IN ULONG NumberOfBytes,
1253 IN PULONG OutLength,
1254 IN BOOLEAN IsValidateLength)
1255 {
1256 struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
1257 ULONG TransferedLength;
1258 NTSTATUS Status;
1259
1260 DPRINT("USBH_SyncGetStringDescriptor: Index - %x, LanguageId - %x\n",
1261 Index,
1262 LanguageId);
1263
1264 Urb = ExAllocatePoolWithTag(NonPagedPool,
1265 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
1266 USB_HUB_TAG);
1267
1268 if (!Urb)
1269 {
1270 return STATUS_INSUFFICIENT_RESOURCES;
1271 }
1272
1273 RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
1274
1275 Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
1276 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
1277
1278 Urb->TransferBuffer = Descriptor;
1279 Urb->TransferBufferLength = NumberOfBytes;
1280
1281 Urb->Index = Index;
1282 Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
1283 Urb->LanguageId = LanguageId;
1284
1285 Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
1286
1287 if (!NT_SUCCESS(Status))
1288 {
1289 ExFreePoolWithTag(Urb, USB_HUB_TAG);
1290 return Status;
1291 }
1292
1293 TransferedLength = Urb->TransferBufferLength;
1294
1295 if (TransferedLength > NumberOfBytes)
1296 {
1297 Status = STATUS_DEVICE_DATA_ERROR;
1298 }
1299
1300 if (!NT_SUCCESS(Status))
1301 {
1302 ExFreePoolWithTag(Urb, USB_HUB_TAG);
1303 return Status;
1304 }
1305
1306 if (OutLength)
1307 {
1308 *OutLength = TransferedLength;
1309 }
1310
1311 if (IsValidateLength && TransferedLength != Descriptor->bLength)
1312 {
1313 Status = STATUS_DEVICE_DATA_ERROR;
1314 }
1315
1316 ExFreePoolWithTag(Urb, USB_HUB_TAG);
1317
1318 return Status;
1319 }
1320
1321 NTSTATUS
1322 NTAPI
1323 USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject,
1324 IN PUSHORT OutStatus,
1325 IN USHORT Function,
1326 IN USHORT RequestIndex)
1327 {
1328 struct _URB_CONTROL_GET_STATUS_REQUEST * Urb;
1329 NTSTATUS NtStatus;
1330 USHORT UsbStatus;
1331
1332 DPRINT("USBH_SyncGetStatus: ... \n");
1333
1334 Urb = ExAllocatePoolWithTag(NonPagedPool,
1335 sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST),
1336 USB_HUB_TAG);
1337
1338 if (!Urb)
1339 {
1340 return STATUS_INSUFFICIENT_RESOURCES;
1341 }
1342
1343 RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
1344
1345 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
1346 Urb->Hdr.Function = Function;
1347
1348 Urb->TransferBuffer = &UsbStatus;
1349 Urb->TransferBufferLength = sizeof(UsbStatus);
1350 Urb->Index = RequestIndex;
1351
1352 NtStatus = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
1353
1354 *OutStatus = UsbStatus;
1355
1356 ExFreePoolWithTag(Urb, USB_HUB_TAG);
1357
1358 return NtStatus;
1359 }
1360
1361 NTSTATUS
1362 NTAPI
1363 USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1364 IN USHORT Port,
1365 IN PUSB_PORT_STATUS_AND_CHANGE PortStatus,
1366 IN ULONG Length)
1367 {
1368 BM_REQUEST_TYPE RequestType;
1369
1370 DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port);
1371
1372 RequestType.B = 0;
1373 RequestType.Recipient = BMREQUEST_TO_OTHER;
1374 RequestType.Type = BMREQUEST_CLASS;
1375 RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1376
1377 return USBH_Transact(HubExtension,
1378 PortStatus,
1379 Length,
1380 BMREQUEST_DEVICE_TO_HOST,
1381 URB_FUNCTION_CLASS_OTHER,
1382 RequestType,
1383 USB_REQUEST_GET_STATUS,
1384 0,
1385 Port);
1386 }
1387
1388
1389 NTSTATUS
1390 NTAPI
1391 USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1392 IN USHORT Port,
1393 IN USHORT RequestValue)
1394 {
1395 BM_REQUEST_TYPE RequestType;
1396
1397 DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n",
1398 Port,
1399 RequestValue);
1400
1401 RequestType.B = 0;
1402 RequestType.Recipient = BMREQUEST_TO_DEVICE;
1403 RequestType.Type = BMREQUEST_CLASS;
1404 RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1405
1406 return USBH_Transact(HubExtension,
1407 NULL,
1408 0,
1409 BMREQUEST_HOST_TO_DEVICE,
1410 URB_FUNCTION_CLASS_OTHER,
1411 RequestType,
1412 USB_REQUEST_CLEAR_FEATURE,
1413 RequestValue,
1414 Port);
1415 }
1416
1417 NTSTATUS
1418 NTAPI
1419 USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
1420 IN USHORT Port,
1421 IN BOOLEAN IsWait)
1422 {
1423 PUSBHUB_PORT_DATA PortData;
1424 PUSB_HUB_DESCRIPTOR HubDescriptor;
1425 NTSTATUS Status = STATUS_SUCCESS;
1426 BM_REQUEST_TYPE RequestType;
1427 PUSB_PORT_STATUS_AND_CHANGE PortStatus;
1428
1429 DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait);
1430
1431 ASSERT(Port > 0);
1432 PortData = &HubExtension->PortData[Port - 1];
1433 PortStatus = &PortData->PortStatus;
1434
1435 if (PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus == 1)
1436 {
1437 return Status;
1438 }
1439
1440 RequestType.B = 0;
1441 RequestType.Recipient = BMREQUEST_TO_DEVICE;
1442 RequestType.Type = BMREQUEST_CLASS;
1443 RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1444
1445 Status = USBH_Transact(HubExtension,
1446 NULL,
1447 0,
1448 BMREQUEST_HOST_TO_DEVICE,
1449 URB_FUNCTION_CLASS_OTHER,
1450 RequestType,
1451 USB_REQUEST_SET_FEATURE,
1452 USBHUB_FEATURE_PORT_POWER,
1453 Port);
1454
1455 if (NT_SUCCESS(Status))
1456 {
1457 if (IsWait)
1458 {
1459 HubDescriptor = HubExtension->HubDescriptor;
1460 USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
1461 }
1462
1463 PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
1464 }
1465
1466 return Status;
1467 }
1468
1469 NTSTATUS
1470 NTAPI
1471 USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)
1472 {
1473 PUSB_HUB_DESCRIPTOR HubDescriptor;
1474 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1475 USHORT Port;
1476 UCHAR NumberOfPorts;
1477
1478 DPRINT("USBH_SyncPowerOnPorts: ... \n");
1479
1480 HubDescriptor = HubExtension->HubDescriptor;
1481 NumberOfPorts = HubDescriptor->bNumberOfPorts;
1482
1483 for (Port = 1; Port <= NumberOfPorts; ++Port)
1484 {
1485 Status = USBH_SyncPowerOnPort(HubExtension, Port, 0);
1486
1487 if (!NT_SUCCESS(Status))
1488 {
1489 DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %lX\n",
1490 Status);
1491 break;
1492 }
1493 }
1494
1495 USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
1496
1497 return Status;
1498 }
1499
1500 NTSTATUS
1501 NTAPI
1502 USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,
1503 IN USHORT Port)
1504 {
1505 PUSBHUB_PORT_DATA PortData;
1506 NTSTATUS Status;
1507 BM_REQUEST_TYPE RequestType;
1508
1509 DPRINT("USBH_SyncDisablePort ... \n");
1510
1511 PortData = &HubExtension->PortData[Port - 1];
1512
1513 RequestType.B = 0;
1514 RequestType.Recipient = BMREQUEST_TO_DEVICE;
1515 RequestType.Type = BMREQUEST_CLASS;
1516 RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1517
1518 Status = USBH_Transact(HubExtension,
1519 NULL,
1520 0,
1521 BMREQUEST_HOST_TO_DEVICE,
1522 URB_FUNCTION_CLASS_OTHER,
1523 RequestType,
1524 USB_REQUEST_CLEAR_FEATURE,
1525 USBHUB_FEATURE_PORT_ENABLE,
1526 Port);
1527
1528 if (NT_SUCCESS(Status))
1529 {
1530 PortData->PortStatus.PortStatus.Usb20PortStatus.PortEnabledDisabled = 0;
1531 }
1532
1533 return Status;
1534 }
1535
1536 BOOLEAN
1537 NTAPI
1538 USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,
1539 IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)
1540 {
1541 BOOLEAN Result;
1542 USHORT UsbStatus;
1543 NTSTATUS Status;
1544
1545 DPRINT("USBH_HubIsBusPowered: ... \n");
1546
1547 Status = USBH_SyncGetStatus(DeviceObject,
1548 &UsbStatus,
1549 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1550 0);
1551
1552 if (!NT_SUCCESS(Status))
1553 {
1554 Result = (HubConfigDescriptor->bmAttributes & USB_CONFIG_POWERED_MASK)
1555 == USB_CONFIG_BUS_POWERED;
1556 }
1557 else
1558 {
1559 Result = (UsbStatus & USB_GETSTATUS_SELF_POWERED) == 0;
1560 }
1561
1562 return Result;
1563 }
1564
1565 NTSTATUS
1566 NTAPI
1567 USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,
1568 IN PIRP Irp,
1569 IN PVOID Context)
1570 {
1571 PUSBHUB_FDO_EXTENSION HubExtension;
1572 PVOID Event;
1573 USHORT Port;
1574
1575 HubExtension = Context;
1576
1577 DPRINT_SCE("USBH_ChangeIndicationAckChangeComplete: ... \n");
1578
1579 ASSERT(HubExtension->Port > 0);
1580 Port = HubExtension->Port - 1;
1581
1582 HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus;
1583
1584 Event = InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
1585 NULL);
1586
1587 if (Event)
1588 {
1589 KeSetEvent(Event, EVENT_INCREMENT, FALSE);
1590 }
1591
1592 USBH_SubmitStatusChangeTransfer(HubExtension);
1593
1594 if (!InterlockedDecrement(&HubExtension->ResetRequestCount))
1595 {
1596 KeSetEvent(&HubExtension->ResetEvent,
1597 EVENT_INCREMENT,
1598 FALSE);
1599 }
1600
1601 return STATUS_MORE_PROCESSING_REQUIRED;
1602 }
1603
1604 NTSTATUS
1605 NTAPI
1606 USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1607 IN PIRP Irp,
1608 IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
1609 IN USHORT Port,
1610 IN USHORT RequestValue)
1611 {
1612 PIO_STACK_LOCATION IoStack;
1613 BM_REQUEST_TYPE RequestType;
1614
1615 DPRINT_SCE("USBH_ChangeIndicationAckChange: ... \n");
1616
1617 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
1618 Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
1619 Urb->Hdr.UsbdDeviceHandle = NULL;
1620
1621 Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
1622 Urb->TransferBufferLength = 0;
1623 Urb->TransferBuffer = NULL;
1624 Urb->TransferBufferMDL = NULL;
1625 Urb->UrbLink = NULL;
1626
1627 RequestType.B = 0;
1628 RequestType.Recipient = BMREQUEST_TO_OTHER;
1629 RequestType.Type = BMREQUEST_CLASS;
1630 RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1631
1632 Urb->RequestTypeReservedBits = RequestType.B;
1633 Urb->Request = USB_REQUEST_CLEAR_FEATURE;
1634 Urb->Index = Port;
1635 Urb->Value = RequestValue;
1636
1637 IoInitializeIrp(Irp,
1638 IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
1639 HubExtension->LowerDevice->StackSize);
1640
1641 IoStack = IoGetNextIrpStackLocation(Irp);
1642
1643 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1644 IoStack->Parameters.Others.Argument1 = Urb;
1645 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
1646
1647 IoSetCompletionRoutine(Irp,
1648 USBH_ChangeIndicationAckChangeComplete,
1649 HubExtension,
1650 TRUE,
1651 TRUE,
1652 TRUE);
1653
1654 return IoCallDriver(HubExtension->LowerDevice, Irp);
1655 }
1656
1657 NTSTATUS
1658 NTAPI
1659 USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,
1660 IN PIRP Irp,
1661 IN PVOID Context)
1662 {
1663 PUSBHUB_FDO_EXTENSION HubExtension;
1664 PUSBHUB_IO_WORK_ITEM WorkItem;
1665 USHORT RequestValue;
1666
1667 HubExtension = Context;
1668
1669 DPRINT_SCE("USBH_ChangeIndicationProcessChange: PortStatus - %lX\n",
1670 HubExtension->PortStatus.AsUlong32);
1671
1672 if ((NT_SUCCESS(Irp->IoStatus.Status) ||
1673 USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) &&
1674 (HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange ||
1675 HubExtension->PortStatus.PortChange.Usb20PortChange.PortEnableDisableChange))
1676 {
1677 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
1678 {
1679 KeSetEvent(&HubExtension->PendingRequestEvent,
1680 EVENT_INCREMENT,
1681 FALSE);
1682 }
1683
1684 USBH_FreeWorkItem(HubExtension->WorkItemToQueue);
1685
1686 HubExtension->WorkItemToQueue = NULL;
1687
1688 if (HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange)
1689 {
1690 RequestValue = USBHUB_FEATURE_C_PORT_RESET;
1691 }
1692 else
1693 {
1694 RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
1695 }
1696
1697 USBH_ChangeIndicationAckChange(HubExtension,
1698 HubExtension->ResetPortIrp,
1699 &HubExtension->SCEWorkerUrb,
1700 HubExtension->Port,
1701 RequestValue);
1702 }
1703 else
1704 {
1705 ASSERT(HubExtension->WorkItemToQueue != NULL);
1706
1707 WorkItem = HubExtension->WorkItemToQueue;
1708 HubExtension->WorkItemToQueue = NULL;
1709
1710 USBH_QueueWorkItem(HubExtension, WorkItem);
1711 }
1712
1713 return STATUS_MORE_PROCESSING_REQUIRED;
1714 }
1715
1716 NTSTATUS
1717 NTAPI
1718 USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1719 IN PIRP Irp,
1720 IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
1721 IN USHORT Port)
1722 {
1723 PUSBHUB_IO_WORK_ITEM WorkItem;
1724 NTSTATUS Status;
1725 PIO_STACK_LOCATION IoStack;
1726 BM_REQUEST_TYPE RequestType;
1727
1728 DPRINT_SCE("USBH_ChangeIndicationQueryChange: Port - %x\n", Port);
1729
1730 InterlockedIncrement(&HubExtension->PendingRequestCount);
1731
1732 if (!Port)
1733 {
1734 ASSERT(HubExtension->WorkItemToQueue != NULL);
1735
1736 WorkItem = HubExtension->WorkItemToQueue;
1737 HubExtension->WorkItemToQueue = NULL;
1738
1739 USBH_QueueWorkItem(HubExtension, WorkItem);
1740
1741 return STATUS_SUCCESS;
1742 }
1743
1744 Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
1745 Urb->Hdr.UsbdDeviceHandle = NULL;
1746 Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
1747
1748 Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
1749 Urb->TransferBuffer = &HubExtension->PortStatus;
1750 Urb->TransferBufferLength = sizeof(HubExtension->PortStatus);
1751 Urb->TransferBufferMDL = NULL;
1752 Urb->UrbLink = NULL;
1753
1754 RequestType.B = 0;
1755 RequestType.Recipient = BMREQUEST_TO_OTHER;
1756 RequestType.Type = BMREQUEST_CLASS;
1757 RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1758
1759 Urb->RequestTypeReservedBits = RequestType.B;
1760 Urb->Request = USB_REQUEST_GET_STATUS;
1761 Urb->Value = 0;
1762 Urb->Index = Port;
1763
1764 HubExtension->Port = Port;
1765
1766 IoInitializeIrp(Irp,
1767 IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
1768 HubExtension->LowerDevice->StackSize);
1769
1770 IoStack = IoGetNextIrpStackLocation(Irp);
1771
1772 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1773 IoStack->Parameters.Others.Argument1 = Urb;
1774 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
1775
1776 IoSetCompletionRoutine(Irp,
1777 USBH_ChangeIndicationProcessChange,
1778 HubExtension,
1779 TRUE,
1780 TRUE,
1781 TRUE);
1782
1783 Status = IoCallDriver(HubExtension->LowerDevice, Irp);
1784
1785 return Status;
1786 }
1787
1788 VOID
1789 NTAPI
1790 USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1791 IN USHORT Port,
1792 IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)
1793 {
1794 PUSBHUB_PORT_DATA PortData;
1795 USB_20_PORT_CHANGE PortStatusChange;
1796 PDEVICE_OBJECT PortDevice;
1797 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
1798 PVOID SerialNumber;
1799 PVOID DeviceHandle;
1800 USHORT RequestValue;
1801 KIRQL Irql;
1802
1803 DPRINT_SCE("USBH_ProcessPortStateChange ... \n");
1804
1805 ASSERT(Port > 0);
1806 PortData = &HubExtension->PortData[Port - 1];
1807
1808 PortStatusChange = PortStatus->PortChange.Usb20PortChange;
1809
1810 if (PortStatusChange.ConnectStatusChange)
1811 {
1812 PortData->PortStatus = *PortStatus;
1813
1814 USBH_SyncClearPortStatus(HubExtension,
1815 Port,
1816 USBHUB_FEATURE_C_PORT_CONNECTION);
1817
1818 PortData = &HubExtension->PortData[Port - 1];
1819
1820 PortDevice = PortData->DeviceObject;
1821
1822 if (!PortDevice)
1823 {
1824 IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1825 return;
1826 }
1827
1828 PortExtension = PortDevice->DeviceExtension;
1829
1830 if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
1831 {
1832 return;
1833 }
1834
1835 KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql);
1836
1837 if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
1838 {
1839 KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
1840 IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1841 return;
1842 }
1843
1844 PortData->DeviceObject = NULL;
1845 PortData->ConnectionStatus = NoDeviceConnected;
1846
1847 HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING;
1848
1849 InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink);
1850
1851 KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
1852
1853 SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
1854 NULL);
1855
1856 if (SerialNumber)
1857 {
1858 ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
1859 }
1860
1861 DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
1862 NULL);
1863
1864 if (DeviceHandle)
1865 {
1866 USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
1867 USBH_SyncDisablePort(HubExtension, Port);
1868 }
1869
1870 IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1871 }
1872 else if (PortStatusChange.PortEnableDisableChange)
1873 {
1874 RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
1875 PortData->PortStatus = *PortStatus;
1876 USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
1877 return;
1878 }
1879 else if (PortStatusChange.SuspendChange)
1880 {
1881 DPRINT1("USBH_ProcessPortStateChange: SuspendChange UNIMPLEMENTED. FIXME\n");
1882 DbgBreakPoint();
1883 }
1884 else if (PortStatusChange.OverCurrentIndicatorChange)
1885 {
1886 DPRINT1("USBH_ProcessPortStateChange: OverCurrentIndicatorChange UNIMPLEMENTED. FIXME\n");
1887 DbgBreakPoint();
1888 }
1889 else if (PortStatusChange.ResetChange)
1890 {
1891 RequestValue = USBHUB_FEATURE_C_PORT_RESET;
1892 PortData->PortStatus = *PortStatus;
1893 USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
1894 }
1895 }
1896
1897 NTSTATUS
1898 NTAPI
1899 USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1900 IN PULONG PortStatus)
1901 {
1902 PIRP Irp;
1903 PIO_STACK_LOCATION IoStack;
1904 NTSTATUS Status;
1905 KEVENT Event;
1906 IO_STATUS_BLOCK IoStatusBlock;
1907
1908 DPRINT("USBH_GetPortStatus ... \n");
1909
1910 *PortStatus = 0;
1911
1912 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1913
1914 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
1915 HubExtension->LowerDevice,
1916 NULL,
1917 0,
1918 NULL,
1919 0,
1920 TRUE,
1921 &Event,
1922 &IoStatusBlock);
1923
1924 if (!Irp)
1925 {
1926 return STATUS_INSUFFICIENT_RESOURCES;
1927 }
1928
1929 IoStack = IoGetNextIrpStackLocation(Irp);
1930 IoStack->Parameters.Others.Argument1 = PortStatus;
1931
1932 Status = IoCallDriver(HubExtension->LowerDevice, Irp);
1933
1934 if (Status == STATUS_PENDING)
1935 {
1936 KeWaitForSingleObject(&Event,
1937 Suspended,
1938 KernelMode,
1939 FALSE,
1940 NULL);
1941 }
1942 else
1943 {
1944 IoStatusBlock.Status = Status;
1945 }
1946
1947 return IoStatusBlock.Status;
1948 }
1949
1950 NTSTATUS
1951 NTAPI
1952 USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)
1953 {
1954 PIRP Irp;
1955 NTSTATUS Status;
1956 KEVENT Event;
1957 IO_STATUS_BLOCK IoStatusBlock;
1958
1959 DPRINT("USBH_EnableParentPort ... \n");
1960
1961 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1962
1963 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT,
1964 HubExtension->LowerDevice,
1965 NULL,
1966 0,
1967 NULL,
1968 0,
1969 TRUE,
1970 &Event,
1971 &IoStatusBlock);
1972
1973 if (!Irp)
1974 {
1975 return STATUS_INSUFFICIENT_RESOURCES;
1976 }
1977
1978 Status = IoCallDriver(HubExtension->LowerDevice, Irp);
1979
1980 if (Status == STATUS_PENDING)
1981 {
1982 KeWaitForSingleObject(&Event,
1983 Suspended,
1984 KernelMode,
1985 FALSE,
1986 NULL);
1987 }
1988 else
1989 {
1990 IoStatusBlock.Status = Status;
1991 }
1992
1993 return IoStatusBlock.Status;
1994 }
1995
1996 NTSTATUS
1997 NTAPI
1998 USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
1999 {
2000 struct _URB_PIPE_REQUEST * Urb;
2001 NTSTATUS Status;
2002
2003 DPRINT("USBH_ResetInterruptPipe ... \n");
2004
2005 Urb = ExAllocatePoolWithTag(NonPagedPool,
2006 sizeof(struct _URB_PIPE_REQUEST),
2007 USB_HUB_TAG);
2008
2009 if (Urb)
2010 {
2011 RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
2012
2013 Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
2014 Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
2015 Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
2016
2017 Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
2018 (PURB)Urb);
2019
2020 ExFreePoolWithTag(Urb, USB_HUB_TAG);
2021 }
2022 else
2023 {
2024 Status = STATUS_INSUFFICIENT_RESOURCES;
2025 }
2026
2027 if (NT_SUCCESS(Status))
2028 {
2029 HubExtension->RequestErrors = 0;
2030 }
2031
2032 return Status;
2033 }
2034
2035 NTSTATUS
2036 NTAPI
2037 USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)
2038 {
2039 NTSTATUS Status;
2040 ULONG PortStatusFlags = 0;
2041
2042 DPRINT("USBH_ResetHub: ... \n");
2043
2044 Status = USBH_GetPortStatus(HubExtension, &PortStatusFlags);
2045
2046 if (!NT_SUCCESS(Status))
2047 {
2048 return Status;
2049 }
2050
2051 if (!(PortStatusFlags & USBD_PORT_ENABLED))
2052 {
2053 if (PortStatusFlags & USBD_PORT_CONNECTED)
2054 {
2055 USBH_EnableParentPort(HubExtension);
2056 }
2057 }
2058
2059 Status = USBH_ResetInterruptPipe(HubExtension);
2060
2061 return Status;
2062 }
2063
2064 VOID
2065 NTAPI
2066 USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
2067 IN PVOID Context)
2068 {
2069 PUSBHUB_FDO_EXTENSION LowerHubExtension;
2070 PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension;
2071 PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem;
2072 USB_PORT_STATUS_AND_CHANGE PortStatus;
2073 NTSTATUS Status;
2074 USHORT Port = 0;
2075
2076 DPRINT_SCE("USBH_ChangeIndicationWorker ... \n");
2077
2078 WorkItem = Context;
2079
2080 KeWaitForSingleObject(&HubExtension->HubSemaphore,
2081 Executive,
2082 KernelMode,
2083 FALSE,
2084 NULL);
2085
2086 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)
2087 {
2088 KeSetEvent(&HubExtension->StatusChangeEvent,
2089 EVENT_INCREMENT,
2090 FALSE);
2091
2092 goto Exit;
2093 }
2094
2095 if (!HubExtension->RequestErrors)
2096 {
2097 goto Enum;
2098 }
2099
2100 DPRINT_SCE("USBH_ChangeIndicationWorker: RequestErrors - %x\n",
2101 HubExtension->RequestErrors);
2102
2103 if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
2104 {
2105 goto Enum;
2106 }
2107
2108 LowerPortExtension = HubExtension->LowerPDO->DeviceExtension;
2109
2110 if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2)
2111 {
2112 goto Enum;
2113 }
2114
2115 LowerHubExtension = LowerPortExtension->HubExtension;
2116
2117 if (!LowerHubExtension)
2118 {
2119 goto Enum;
2120 }
2121
2122 Status = USBH_SyncGetPortStatus(LowerHubExtension,
2123 LowerPortExtension->PortNumber,
2124 &PortStatus,
2125 sizeof(USB_PORT_STATUS_AND_CHANGE));
2126
2127 if (!NT_SUCCESS(Status) ||
2128 !PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
2129 {
2130 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
2131
2132 KeSetEvent(&HubExtension->StatusChangeEvent,
2133 EVENT_INCREMENT,
2134 FALSE);
2135
2136 goto Exit;
2137 }
2138
2139 if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING))
2140 {
2141 HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING;
2142
2143 DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME\n");
2144 DbgBreakPoint();
2145
2146 goto Exit;
2147 }
2148
2149 Enum:
2150
2151 if (WorkItem->IsRequestErrors)
2152 {
2153 USBH_ResetHub(HubExtension);
2154 }
2155 else
2156 {
2157 for (Port = 0;
2158 Port < HubExtension->HubDescriptor->bNumberOfPorts;
2159 Port++)
2160 {
2161 if (IsBitSet((PUCHAR)(WorkItem + 1), Port))
2162 {
2163 break;
2164 }
2165 }
2166
2167 if (Port)
2168 {
2169 Status = USBH_SyncGetPortStatus(HubExtension,
2170 Port,
2171 &PortStatus,
2172 sizeof(USB_PORT_STATUS_AND_CHANGE));
2173 }
2174 else
2175 {
2176 DPRINT1("USBH_ChangeIndicationWorker: USBH_SyncGetHubStatus() UNIMPLEMENTED. FIXME\n");
2177 DbgBreakPoint();
2178 Status = STATUS_ASSERTION_FAILURE;
2179 }
2180
2181 if (NT_SUCCESS(Status))
2182 {
2183 if (Port)
2184 {
2185 USBH_ProcessPortStateChange(HubExtension,
2186 Port,
2187 &PortStatus);
2188 }
2189 else
2190 {
2191 DPRINT1("USBH_ChangeIndicationWorker: USBH_ProcessHubStateChange() UNIMPLEMENTED. FIXME\n");
2192 DbgBreakPoint();
2193 }
2194 }
2195 else
2196 {
2197 HubExtension->RequestErrors++;
2198
2199 if (HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS)
2200 {
2201 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
2202 goto Exit;
2203 }
2204 }
2205 }
2206
2207 USBH_SubmitStatusChangeTransfer(HubExtension);
2208
2209 Exit:
2210
2211 KeReleaseSemaphore(&HubExtension->HubSemaphore,
2212 LOW_REALTIME_PRIORITY,
2213 1,
2214 FALSE);
2215
2216 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
2217 {
2218 KeSetEvent(&HubExtension->PendingRequestEvent,
2219 EVENT_INCREMENT,
2220 FALSE);
2221 }
2222
2223 if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount))
2224 {
2225 KeSetEvent(&HubExtension->ResetEvent,
2226 EVENT_INCREMENT,
2227 FALSE);
2228
2229 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE)
2230 {
2231 USBH_CheckHubIdle(HubExtension);
2232 }
2233 }
2234 }
2235
2236 NTSTATUS
2237 NTAPI
2238 USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,
2239 IN PIRP Irp,
2240 IN PVOID Context)
2241 {
2242 PUSBHUB_FDO_EXTENSION HubExtension;
2243 USBD_STATUS UrbStatus;
2244 BOOLEAN IsErrors = FALSE;
2245 PUSBHUB_IO_WORK_ITEM HubWorkItem;
2246 PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer;
2247 USHORT NumPorts;
2248 USHORT Port;
2249 NTSTATUS Status;
2250 PVOID Bitmap;
2251 ULONG BufferLength;
2252
2253 HubExtension = Context;
2254 UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status;
2255
2256 DPRINT_SCE("USBH_ChangeIndication: IrpStatus - %x, UrbStatus - %x, HubFlags - %lX\n",
2257 Irp->IoStatus.Status,
2258 UrbStatus,
2259 HubExtension->HubFlags);
2260
2261 if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) ||
2262 (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) ||
2263 (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING))
2264 {
2265 HubExtension->RequestErrors++;
2266
2267 IsErrors = TRUE;
2268
2269 KeSetEvent(&HubExtension->StatusChangeEvent,
2270 EVENT_INCREMENT,
2271 FALSE);
2272
2273 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
2274 HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
2275 HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS ||
2276 Irp->IoStatus.Status == STATUS_DELETE_PENDING)
2277 {
2278 DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
2279 HubExtension->RequestErrors);
2280
2281 return STATUS_MORE_PROCESSING_REQUIRED;
2282 }
2283
2284 DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
2285 HubExtension->RequestErrors);
2286 }
2287 else
2288 {
2289 HubExtension->RequestErrors = 0;
2290 }
2291
2292 BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) +
2293 HubExtension->SCEBitmapLength;
2294
2295 Status = USBH_AllocateWorkItem(HubExtension,
2296 &HubWorkItem,
2297 USBH_ChangeIndicationWorker,
2298 BufferLength,
2299 (PVOID *)&HubWorkItemBuffer,
2300 DelayedWorkQueue);
2301
2302 if (!NT_SUCCESS(Status))
2303 {
2304 return STATUS_MORE_PROCESSING_REQUIRED;
2305 }
2306
2307 RtlZeroMemory(HubWorkItemBuffer, BufferLength);
2308
2309 HubWorkItemBuffer->IsRequestErrors = FALSE;
2310
2311 if (IsErrors)
2312 {
2313 HubWorkItemBuffer->IsRequestErrors = TRUE;
2314 }
2315
2316 if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1)
2317 {
2318 KeResetEvent(&HubExtension->ResetEvent);
2319 }
2320
2321 HubWorkItemBuffer->HubExtension = HubExtension;
2322
2323 HubExtension->WorkItemToQueue = HubWorkItem;
2324
2325 Bitmap = HubWorkItemBuffer + 1;
2326
2327 RtlCopyMemory(Bitmap,
2328 HubExtension->SCEBitmap,
2329 HubExtension->SCEBitmapLength);
2330
2331 NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
2332
2333 for (Port = 0; Port <= NumPorts; ++Port)
2334 {
2335 if (IsBitSet(Bitmap, Port))
2336 {
2337 break;
2338 }
2339 }
2340
2341 if (Port > NumPorts)
2342 {
2343 Port = 0;
2344 }
2345
2346 Status = USBH_ChangeIndicationQueryChange(HubExtension,
2347 HubExtension->ResetPortIrp,
2348 &HubExtension->SCEWorkerUrb,
2349 Port);
2350
2351 if (NT_ERROR(Status))
2352 {
2353 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
2354 }
2355
2356 return STATUS_MORE_PROCESSING_REQUIRED;
2357 }
2358
2359 NTSTATUS
2360 NTAPI
2361 USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)
2362 {
2363 PIRP Irp;
2364 NTSTATUS Status;
2365 struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb;
2366 PIO_STACK_LOCATION IoStack;
2367
2368 DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n",
2369 HubExtension,
2370 HubExtension->SCEIrp);
2371
2372 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE)
2373 {
2374 DPRINT_SCE("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE\n");
2375 DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubFlags - %lX\n",
2376 HubExtension->HubFlags);
2377
2378 return STATUS_INVALID_DEVICE_STATE;
2379 }
2380
2381 Irp = HubExtension->SCEIrp;
2382
2383 if (!Irp)
2384 {
2385 return STATUS_INVALID_DEVICE_STATE;
2386 }
2387
2388 Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb;
2389
2390 Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
2391 Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
2392 Urb->Hdr.UsbdDeviceHandle = NULL;
2393
2394 Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
2395 Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
2396 Urb->TransferBuffer = HubExtension->SCEBitmap;
2397 Urb->TransferBufferLength = HubExtension->SCEBitmapLength;
2398 Urb->TransferBufferMDL = NULL;
2399 Urb->UrbLink = NULL;
2400
2401 IoInitializeIrp(Irp,
2402 IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
2403 HubExtension->LowerDevice->StackSize);
2404
2405 IoStack = IoGetNextIrpStackLocation(Irp);
2406
2407 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
2408 IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb;
2409 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
2410
2411 IoSetCompletionRoutine(Irp,
2412 USBH_ChangeIndication,
2413 HubExtension,
2414 TRUE,
2415 TRUE,
2416 TRUE);
2417
2418 KeResetEvent(&HubExtension->StatusChangeEvent);
2419
2420 Status = IoCallDriver(HubExtension->LowerDevice, Irp);
2421
2422 return Status;
2423 }
2424
2425 NTSTATUS
2426 NTAPI
2427 USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2428 IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
2429 IN USB_PORT_STATUS UsbPortStatus,
2430 IN USHORT Port)
2431 {
2432 PUSB_DEVICE_HANDLE HubDeviceHandle;
2433 PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice;
2434
2435 DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n",
2436 Port,
2437 UsbPortStatus.AsUshort16);
2438
2439 CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice;
2440
2441 if (!CreateUsbDevice)
2442 {
2443 return STATUS_NOT_IMPLEMENTED;
2444 }
2445
2446 HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
2447
2448 return CreateUsbDevice(HubExtension->BusInterface.BusContext,
2449 OutDeviceHandle,
2450 HubDeviceHandle,
2451 UsbPortStatus.AsUshort16,
2452 Port);
2453 }
2454
2455 NTSTATUS
2456 NTAPI
2457 USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2458 IN PUSB_DEVICE_HANDLE DeviceHandle,
2459 IN ULONG Flags)
2460 {
2461 PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice;
2462
2463 DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %X\n",
2464 DeviceHandle,
2465 Flags);
2466
2467 RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice;
2468
2469 if (!RemoveUsbDevice)
2470 {
2471 return STATUS_NOT_IMPLEMENTED;
2472 }
2473
2474 return RemoveUsbDevice(HubExtension->BusInterface.BusContext,
2475 DeviceHandle,
2476 Flags);
2477 }
2478
2479 NTSTATUS
2480 NTAPI
2481 USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2482 IN PUSB_DEVICE_HANDLE DeviceHandle,
2483 IN PUCHAR DeviceDescriptorBuffer,
2484 IN ULONG DeviceDescriptorBufferLength,
2485 IN PUCHAR ConfigDescriptorBuffer,
2486 IN ULONG ConfigDescriptorBufferLength)
2487 {
2488 NTSTATUS Status;
2489 PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice;
2490 PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors;
2491
2492 DPRINT("USBD_InitializeDeviceEx: ... \n");
2493
2494 InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice;
2495 GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors;
2496
2497 if (!InitializeUsbDevice || !GetUsbDescriptors)
2498 {
2499 return STATUS_NOT_IMPLEMENTED;
2500 }
2501
2502 Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext,
2503 DeviceHandle);
2504
2505 if (!NT_SUCCESS(Status))
2506 {
2507 return Status;
2508 }
2509
2510 return GetUsbDescriptors(HubExtension->BusInterface.BusContext,
2511 DeviceHandle,
2512 DeviceDescriptorBuffer,
2513 &DeviceDescriptorBufferLength,
2514 ConfigDescriptorBuffer,
2515 &ConfigDescriptorBufferLength);
2516 }
2517
2518 VOID
2519 NTAPI
2520 USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,
2521 IN PDEVICE_OBJECT UsbDevicePdo,
2522 IN PVOID DeviceHandle)
2523 {
2524 PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData;
2525
2526 DPRINT("USBHUB_SetDeviceHandleData ... \n");
2527
2528 SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData;
2529
2530 if (!SetDeviceHandleData)
2531 {
2532 return;
2533 }
2534
2535 SetDeviceHandleData(HubExtension->BusInterface.BusContext,
2536 DeviceHandle,
2537 UsbDevicePdo);
2538 }
2539
2540 VOID
2541 NTAPI
2542 USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)
2543 {
2544 PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers;
2545
2546 DPRINT("USBHUB_FlushAllTransfers ... \n");
2547
2548 FlushTransfers = HubExtension->BusInterface.FlushTransfers;
2549
2550 if (FlushTransfers)
2551 {
2552 FlushTransfers(HubExtension->BusInterface.BusContext, NULL);
2553 }
2554 }
2555
2556 NTSTATUS
2557 NTAPI
2558 USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2559 IN PUSBHUB_FDO_EXTENSION HubExtension,
2560 IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
2561 IN ULONG Length,
2562 IN PUSB_DEVICE_HANDLE DeviceHandle)
2563 {
2564 PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
2565 PUSB_DEVICE_INFORMATION_0 DeviceInfo;
2566 SIZE_T DeviceInfoLength;
2567 PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo;
2568 SIZE_T NodeInfoLength;
2569 ULONG PipeNumber;
2570 ULONG dummy;
2571 NTSTATUS Status;
2572
2573 DPRINT("USBD_GetDeviceInformationEx ... \n");
2574
2575 QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
2576
2577 if (!QueryDeviceInformation)
2578 {
2579 Status = STATUS_NOT_IMPLEMENTED;
2580 return Status;
2581 }
2582
2583 DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0);
2584
2585 while (TRUE)
2586 {
2587 DeviceInfo = ExAllocatePoolWithTag(PagedPool,
2588 DeviceInfoLength,
2589 USB_HUB_TAG);
2590
2591 if (!DeviceInfo)
2592 {
2593 return STATUS_INSUFFICIENT_RESOURCES;
2594 }
2595
2596 RtlZeroMemory(DeviceInfo, DeviceInfoLength);
2597
2598 DeviceInfo->InformationLevel = 0;
2599
2600 Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
2601 DeviceHandle,
2602 DeviceInfo,
2603 DeviceInfoLength,
2604 &dummy);
2605
2606 if (Status != STATUS_BUFFER_TOO_SMALL)
2607 {
2608 break;
2609 }
2610
2611 DeviceInfoLength = DeviceInfo->ActualLength;
2612
2613 ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2614 }
2615
2616 NodeInfo = NULL;
2617 NodeInfoLength = 0;
2618
2619 if (NT_SUCCESS(Status))
2620 {
2621 NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) +
2622 DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO);
2623
2624 NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG);
2625
2626 if (!NodeInfo)
2627 {
2628 ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2629 return STATUS_INSUFFICIENT_RESOURCES;
2630 }
2631
2632 RtlZeroMemory(NodeInfo, NodeInfoLength);
2633
2634 NodeInfo->ConnectionIndex = Info->ConnectionIndex;
2635
2636 RtlCopyMemory(&NodeInfo->DeviceDescriptor,
2637 &DeviceInfo->DeviceDescriptor,
2638 sizeof(USB_DEVICE_DESCRIPTOR));
2639
2640 NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue;
2641 NodeInfo->Speed = DeviceInfo->DeviceSpeed;
2642 NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE;
2643 NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress;
2644 NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes;
2645 NodeInfo->ConnectionStatus = Info->ConnectionStatus;
2646
2647 for (PipeNumber = 0;
2648 PipeNumber < DeviceInfo->NumberOfOpenPipes;
2649 PipeNumber++)
2650 {
2651 RtlCopyMemory(&NodeInfo->PipeList[PipeNumber],
2652 &DeviceInfo->PipeList[PipeNumber],
2653 sizeof(USB_PIPE_INFO));
2654 }
2655 }
2656
2657 ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2658
2659 if (NodeInfo)
2660 {
2661 if (NodeInfoLength <= Length)
2662 {
2663 Length = NodeInfoLength;
2664 }
2665 else
2666 {
2667 Status = STATUS_BUFFER_TOO_SMALL;
2668 }
2669
2670 RtlCopyMemory(Info, NodeInfo, Length);
2671
2672 ExFreePoolWithTag(NodeInfo, USB_HUB_TAG);
2673 }
2674
2675 return Status;
2676 }
2677
2678 NTSTATUS
2679 NTAPI
2680 USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2681 IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
2682 IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)
2683 {
2684 PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice;
2685 NTSTATUS Status;
2686
2687 DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n",
2688 HubExtension,
2689 OldDeviceHandle,
2690 NewDeviceHandle);
2691
2692 RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice;
2693
2694 if (RestoreUsbDevice)
2695 {
2696 Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext,
2697 OldDeviceHandle,
2698 NewDeviceHandle);
2699 }
2700 else
2701 {
2702 Status = STATUS_NOT_IMPLEMENTED;
2703 }
2704
2705 return Status;
2706 }
2707
2708 NTSTATUS
2709 NTAPI
2710 USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,
2711 PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
2712 PUSBHUB_WORKER_ROUTINE WorkerRoutine,
2713 SIZE_T BufferLength,
2714 PVOID * OutHubWorkItemBuffer,
2715 WORK_QUEUE_TYPE Type)
2716 {
2717 PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
2718 PIO_WORKITEM WorkItem;
2719 PVOID WorkItemBuffer;
2720
2721 DPRINT("USBH_AllocateWorkItem: ... \n");
2722
2723 if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT))
2724 {
2725 return STATUS_INVALID_PARAMETER;
2726 }
2727
2728 HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool,
2729 sizeof(USBHUB_IO_WORK_ITEM),
2730 USB_HUB_TAG);
2731
2732 if (!HubIoWorkItem)
2733 {
2734 return STATUS_INSUFFICIENT_RESOURCES;
2735 }
2736
2737 RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM));
2738
2739 WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice);
2740
2741 HubIoWorkItem->HubWorkItem = WorkItem;
2742
2743 if (!WorkItem)
2744 {
2745 ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2746 return STATUS_INSUFFICIENT_RESOURCES;
2747 }
2748
2749 if (BufferLength && OutHubWorkItemBuffer)
2750 {
2751 WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2752 BufferLength,
2753 USB_HUB_TAG);
2754
2755 HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer;
2756
2757 if (!WorkItemBuffer)
2758 {
2759 IoFreeWorkItem(HubIoWorkItem->HubWorkItem);
2760 ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2761
2762 return STATUS_INSUFFICIENT_RESOURCES;
2763 }
2764
2765 RtlZeroMemory(WorkItemBuffer, BufferLength);
2766 }
2767 else
2768 {
2769 HubIoWorkItem->HubWorkItemBuffer = NULL;
2770 }
2771
2772 HubIoWorkItem->HubWorkItemType = Type;
2773 HubIoWorkItem->HubExtension = HubExtension;
2774 HubIoWorkItem->HubWorkerRoutine = WorkerRoutine;
2775
2776 if (OutHubIoWorkItem)
2777 {
2778 *OutHubIoWorkItem = HubIoWorkItem;
2779 }
2780
2781 if (OutHubWorkItemBuffer)
2782 {
2783 *OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer;
2784 }
2785
2786 return STATUS_SUCCESS;
2787 }
2788
2789 VOID
2790 NTAPI
2791 USBH_Worker(IN PDEVICE_OBJECT DeviceObject,
2792 IN PVOID Context)
2793 {
2794 PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
2795 PUSBHUB_FDO_EXTENSION HubExtension;
2796 KIRQL OldIrql;
2797 PIO_WORKITEM WorkItem;
2798
2799 DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context);
2800
2801 HubIoWorkItem = Context;
2802
2803 InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued);
2804
2805 HubExtension = HubIoWorkItem->HubExtension;
2806 WorkItem = HubIoWorkItem->HubWorkItem;
2807
2808 HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension,
2809 HubIoWorkItem->HubWorkItemBuffer);
2810
2811 KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql);
2812 RemoveEntryList(&HubIoWorkItem->HubWorkItemLink);
2813 KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql);
2814
2815 if (HubIoWorkItem->HubWorkItemBuffer)
2816 {
2817 ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
2818 }
2819
2820 ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2821
2822 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
2823 {
2824 KeSetEvent(&HubExtension->PendingRequestEvent,
2825 EVENT_INCREMENT,
2826 FALSE);
2827 }
2828
2829 IoFreeWorkItem(WorkItem);
2830
2831 DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context);
2832 }
2833
2834 VOID
2835 NTAPI
2836 USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,
2837 IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
2838 {
2839 DPRINT("USBH_QueueWorkItem: ... \n");
2840
2841 InterlockedIncrement(&HubExtension->PendingRequestCount);
2842 InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued);
2843
2844 ExInterlockedInsertTailList(&HubExtension->WorkItemList,
2845 &HubIoWorkItem->HubWorkItemLink,
2846 &HubExtension->WorkItemSpinLock);
2847
2848 IoQueueWorkItem(HubIoWorkItem->HubWorkItem,
2849 USBH_Worker,
2850 HubIoWorkItem->HubWorkItemType,
2851 HubIoWorkItem);
2852 }
2853
2854 VOID
2855 NTAPI
2856 USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
2857 {
2858 PIO_WORKITEM WorkItem;
2859
2860 DPRINT("USBH_FreeWorkItem: ... \n");
2861
2862 WorkItem = HubIoWorkItem->HubWorkItem;
2863
2864 if (HubIoWorkItem->HubWorkItemBuffer)
2865 {
2866 ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
2867 }
2868
2869 ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2870
2871 IoFreeWorkItem(WorkItem);
2872 }
2873
2874 VOID
2875 NTAPI
2876 USBHUB_RootHubCallBack(IN PVOID Context)
2877 {
2878 PUSBHUB_FDO_EXTENSION HubExtension;
2879
2880 DPRINT("USBHUB_RootHubCallBack: ... \n");
2881
2882 HubExtension = Context;
2883
2884 if (HubExtension->SCEIrp)
2885 {
2886 HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION |
2887 USBHUB_FDO_FLAG_NOT_ENUMERATED);
2888
2889 USBH_SubmitStatusChangeTransfer(HubExtension);
2890
2891 IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
2892 }
2893 else
2894 {
2895 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
2896 }
2897
2898 KeSetEvent(&HubExtension->RootHubNotificationEvent,
2899 EVENT_INCREMENT,
2900 FALSE);
2901 }
2902
2903 NTSTATUS
2904 NTAPI
2905 USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
2906 {
2907 PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
2908
2909 DPRINT("USBD_RegisterRootHubCallBack: ... \n");
2910
2911 RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
2912
2913 if (!RootHubInitNotification)
2914 {
2915 return STATUS_NOT_IMPLEMENTED;
2916 }
2917
2918 KeResetEvent(&HubExtension->RootHubNotificationEvent);
2919
2920 return RootHubInitNotification(HubExtension->BusInterface.BusContext,
2921 HubExtension,
2922 USBHUB_RootHubCallBack);
2923 }
2924
2925 NTSTATUS
2926 NTAPI
2927 USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
2928 {
2929 PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
2930 NTSTATUS Status;
2931
2932 DPRINT("USBD_UnRegisterRootHubCallBack ... \n");
2933
2934 RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
2935
2936 if (!RootHubInitNotification)
2937 {
2938 return STATUS_NOT_IMPLEMENTED;
2939 }
2940
2941 Status = RootHubInitNotification(HubExtension->BusInterface.BusContext,
2942 NULL,
2943 NULL);
2944
2945 if (!NT_SUCCESS(Status))
2946 {
2947 KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent,
2948 Executive,
2949 KernelMode,
2950 FALSE,
2951 NULL);
2952 }
2953
2954 return Status;
2955 }
2956
2957 VOID
2958 NTAPI
2959 USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,
2960 IN UCHAR MinorFunction,
2961 IN POWER_STATE PowerState,
2962 IN PVOID Context,
2963 IN PIO_STATUS_BLOCK IoStatus)
2964 {
2965 DPRINT("USBH_HubSetDWakeCompletion: ... \n");
2966 KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
2967 }
2968
2969 VOID
2970 NTAPI
2971 USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
2972 IN PLIST_ENTRY IdleList)
2973 {
2974 PDEVICE_OBJECT PortDevice;
2975 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
2976 PIRP IdleIrp;
2977 PIRP HubIdleIrp;
2978 ULONG NumPorts;
2979 ULONG Port;
2980 KIRQL Irql;
2981
2982 DPRINT("USBH_HubQueuePortIdleIrps ... \n");
2983
2984 InitializeListHead(IdleList);
2985
2986 IoAcquireCancelSpinLock(&Irql);
2987
2988 NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
2989
2990 for (Port = 0; Port < NumPorts; ++Port)
2991 {
2992 PortDevice = HubExtension->PortData[Port].DeviceObject;
2993
2994 if (PortDevice)
2995 {
2996 PortExtension = PortDevice->DeviceExtension;
2997
2998 IdleIrp = PortExtension->IdleNotificationIrp;
2999 PortExtension->IdleNotificationIrp = NULL;
3000
3001 if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL))
3002 {
3003 DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME\n");
3004 DbgBreakPoint();
3005 }
3006 }
3007 }
3008
3009 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
3010 {
3011 HubIdleIrp = HubExtension->PendingIdleIrp;
3012 HubExtension->PendingIdleIrp = NULL;
3013 }
3014 else
3015 {
3016 HubIdleIrp = NULL;
3017 }
3018
3019 IoReleaseCancelSpinLock(Irql);
3020
3021 if (HubIdleIrp)
3022 {
3023 USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp);
3024 }
3025 }
3026
3027 VOID
3028 NTAPI
3029 USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
3030 IN PLIST_ENTRY IdleList,
3031 IN NTSTATUS NtStatus)
3032 {
3033 DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n");
3034
3035 while (!IsListEmpty(IdleList))
3036 {
3037 DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME\n");
3038 DbgBreakPoint();
3039 }
3040 }
3041
3042 VOID
3043 NTAPI
3044 USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)
3045 {
3046 PDEVICE_OBJECT PortDevice;
3047 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3048 PLIST_ENTRY Entry;
3049 ULONG Port;
3050
3051 DPRINT("USBH_FlushPortPwrList ... \n");
3052
3053 InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount);
3054
3055 KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3056 Executive,
3057 KernelMode,
3058 FALSE,
3059 NULL);
3060
3061 for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; ++Port)
3062 {
3063 PortDevice = HubExtension->PortData[Port].DeviceObject;
3064
3065 if (!PortDevice)
3066 {
3067 continue;
3068 }
3069
3070 PortExtension = PortDevice->DeviceExtension;
3071
3072 InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0);
3073
3074 while (TRUE)
3075 {
3076 Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList,
3077 &PortExtension->PortPowerListSpinLock);
3078
3079 if (!Entry)
3080 {
3081 break;
3082 }
3083
3084 DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME\n");
3085 DbgBreakPoint();
3086 }
3087 }
3088
3089 KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3090 LOW_REALTIME_PRIORITY,
3091 1,
3092 FALSE);
3093
3094 if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount))
3095 {
3096 KeSetEvent(&HubExtension->PendingRequestEvent,
3097 EVENT_INCREMENT,
3098 FALSE);
3099 }
3100 }
3101
3102 VOID
3103 NTAPI
3104 USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
3105 IN NTSTATUS NtStatus)
3106 {
3107 LIST_ENTRY IdleList;
3108
3109 DPRINT("USBH_HubCompletePortIdleIrps ... \n");
3110
3111 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
3112 {
3113 USBH_HubQueuePortIdleIrps(HubExtension, &IdleList);
3114
3115 USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
3116 &IdleList,
3117 NtStatus);
3118
3119 USBH_FlushPortPwrList(HubExtension);
3120 }
3121 }
3122
3123 VOID
3124 NTAPI
3125 USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
3126 IN PIRP IdleIrp)
3127 {
3128 DPRINT("USBH_HubCancelIdleIrp ... \n");
3129
3130 IoCancelIrp(IdleIrp);
3131
3132 if (InterlockedExchange(&HubExtension->IdleRequestLock, 1))
3133 {
3134 IoFreeIrp(IdleIrp);
3135 }
3136 }
3137
3138 BOOLEAN
3139 NTAPI
3140 USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,
3141 IN BOOLEAN IsWait,
3142 IN BOOLEAN IsExtCheck)
3143 {
3144 PDEVICE_OBJECT PdoDevice;
3145 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3146 PUSBHUB_PORT_DATA PortData;
3147 ULONG Port;
3148 BOOLEAN Result = FALSE;
3149
3150 DPRINT("USBH_CheckIdleAbort: ... \n");
3151
3152 InterlockedIncrement(&HubExtension->PendingRequestCount);
3153
3154 if (IsWait == TRUE)
3155 {
3156 KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3157 Executive,
3158 KernelMode,
3159 FALSE,
3160 NULL);
3161 }
3162
3163 PortData = HubExtension->PortData;
3164
3165 for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
3166 {
3167 PdoDevice = PortData[Port].DeviceObject;
3168
3169 if (PdoDevice)
3170 {
3171 PortExtension = PdoDevice->DeviceExtension;
3172
3173 if (PortExtension->PoRequestCounter)
3174 {
3175 Result = TRUE;
3176 goto Wait;
3177 }
3178 }
3179 }
3180
3181 if (IsExtCheck == TRUE)
3182 {
3183 PortData = HubExtension->PortData;
3184
3185 for (Port = 0;
3186 Port < HubExtension->HubDescriptor->bNumberOfPorts;
3187 Port++)
3188 {
3189 PdoDevice = PortData[Port].DeviceObject;
3190
3191 if (PdoDevice)
3192 {
3193 PortExtension = PdoDevice->DeviceExtension;
3194 InterlockedExchange(&PortExtension->StateBehindD2, 0);
3195 }
3196 }
3197 }
3198
3199 Wait:
3200
3201 if (IsWait == TRUE)
3202 {
3203 KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3204 LOW_REALTIME_PRIORITY,
3205 1,
3206 FALSE);
3207 }
3208
3209 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3210 {
3211 KeSetEvent(&HubExtension->PendingRequestEvent,
3212 EVENT_INCREMENT,
3213 FALSE);
3214 }
3215
3216 return Result;
3217 }
3218
3219 VOID
3220 NTAPI
3221 USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
3222 IN UCHAR MinorFunction,
3223 IN POWER_STATE PowerState,
3224 IN PVOID Context,
3225 IN PIO_STATUS_BLOCK IoStatus)
3226 {
3227 DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n");
3228 }
3229
3230 NTSTATUS
3231 NTAPI
3232 USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
3233 {
3234 POWER_STATE PowerState;
3235 NTSTATUS Status;
3236 PIRP Irp = NULL;
3237 KIRQL Irql;
3238
3239 DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n");
3240
3241 PowerState.SystemState = HubExtension->SystemWake;
3242 HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
3243
3244 InterlockedIncrement(&HubExtension->PendingRequestCount);
3245 InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0);
3246
3247 Status = PoRequestPowerIrp(HubExtension->LowerPDO,
3248 IRP_MN_WAIT_WAKE,
3249 PowerState,
3250 USBH_FdoWaitWakeIrpCompletion,
3251 HubExtension,
3252 &Irp);
3253
3254 IoAcquireCancelSpinLock(&Irql);
3255
3256 if (Status == STATUS_PENDING)
3257 {
3258 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)
3259 {
3260 HubExtension->PendingWakeIrp = Irp;
3261 DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n",
3262 HubExtension->PendingWakeIrp);
3263 }
3264 }
3265 else
3266 {
3267 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
3268
3269 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3270 {
3271 KeSetEvent(&HubExtension->PendingRequestEvent,
3272 EVENT_INCREMENT,
3273 FALSE);
3274 }
3275 }
3276
3277 IoReleaseCancelSpinLock(Irql);
3278
3279 return Status;
3280 }
3281
3282 VOID
3283 NTAPI
3284 USBH_FdoIdleNotificationCallback(IN PVOID Context)
3285 {
3286 PUSBHUB_FDO_EXTENSION HubExtension;
3287 PUSBHUB_PORT_DATA PortData;
3288 PDEVICE_OBJECT PortDevice;
3289 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3290 PIRP Irp = NULL;
3291 PIRP IdleIrp;
3292 POWER_STATE PowerState;
3293 KEVENT Event;
3294 ULONG Port;
3295 PIO_STACK_LOCATION IoStack;
3296 PUSB_IDLE_CALLBACK_INFO CallbackInfo;
3297 BOOLEAN IsReady;
3298 KIRQL OldIrql;
3299 NTSTATUS Status;
3300
3301 HubExtension = Context;
3302
3303 DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %lX\n",
3304 HubExtension,
3305 HubExtension->HubFlags);
3306
3307 if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER |
3308 USBHUB_FDO_FLAG_WAKEUP_START |
3309 USBHUB_FDO_FLAG_DEVICE_REMOVED |
3310 USBHUB_FDO_FLAG_STATE_CHANGING |
3311 USBHUB_FDO_FLAG_ESD_RECOVERING |
3312 USBHUB_FDO_FLAG_DEVICE_FAILED |
3313 USBHUB_FDO_FLAG_DEVICE_STOPPING))
3314 {
3315 DbgBreakPoint();
3316 return;
3317 }
3318
3319 HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE;
3320
3321 if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP))
3322 {
3323 Status = USBH_FdoSubmitWaitWakeIrp(HubExtension);
3324
3325 if (Status != STATUS_PENDING)
3326 {
3327 DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n");
3328 DbgBreakPoint();
3329 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
3330 return;
3331 }
3332 }
3333
3334 InterlockedIncrement(&HubExtension->PendingRequestCount);
3335
3336 KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3337 Executive,
3338 KernelMode,
3339 FALSE,
3340 NULL);
3341
3342 PortData = HubExtension->PortData;
3343 IsReady = TRUE;
3344
3345 for (Port = 0;
3346 Port < HubExtension->HubDescriptor->bNumberOfPorts;
3347 Port++)
3348 {
3349 PortDevice = PortData[Port].DeviceObject;
3350
3351 if (PortDevice)
3352 {
3353 PortExtension = PortDevice->DeviceExtension;
3354
3355 IdleIrp = PortExtension->IdleNotificationIrp;
3356
3357 if (!IdleIrp)
3358 {
3359 IsReady = FALSE;
3360 goto IdleHub;
3361 }
3362
3363 IoStack = IoGetCurrentIrpStackLocation(IdleIrp);
3364
3365 CallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
3366
3367 if (!CallbackInfo)
3368 {
3369 IsReady = FALSE;
3370 goto IdleHub;
3371 }
3372
3373 if (!CallbackInfo->IdleCallback)
3374 {
3375 IsReady = FALSE;
3376 goto IdleHub;
3377 }
3378
3379 if (PortExtension->PendingSystemPoRequest)
3380 {
3381 IsReady = FALSE;
3382 goto IdleHub;
3383 }
3384
3385 if (InterlockedCompareExchange(&PortExtension->StateBehindD2,
3386 1,
3387 0))
3388 {
3389 IsReady = FALSE;
3390 goto IdleHub;
3391 }
3392
3393 DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n",
3394 CallbackInfo->IdleContext);
3395
3396 CallbackInfo->IdleCallback(CallbackInfo->IdleContext);
3397
3398 if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
3399 {
3400 IsReady = FALSE;
3401 goto IdleHub;
3402 }
3403 }
3404 }
3405
3406 if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) &&
3407 (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) == TRUE))
3408 {
3409 IsReady = FALSE;
3410 }
3411
3412 IdleHub:
3413
3414 KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3415 LOW_REALTIME_PRIORITY,
3416 1,
3417 FALSE);
3418
3419 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3420 {
3421 KeSetEvent(&HubExtension->PendingRequestEvent,
3422 EVENT_INCREMENT,
3423 FALSE);
3424 }
3425
3426 if (!IsReady ||
3427 (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED))
3428 {
3429 DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %lX\n",
3430 HubExtension->HubFlags);
3431
3432 HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
3433 USBHUB_FDO_FLAG_GOING_IDLE);
3434
3435 /* Aborting Idle for Hub */
3436 IoAcquireCancelSpinLock(&OldIrql);
3437
3438 if (HubExtension->PendingIdleIrp)
3439 {
3440 Irp = HubExtension->PendingIdleIrp;
3441 HubExtension->PendingIdleIrp = NULL;
3442 }
3443
3444 IoReleaseCancelSpinLock(OldIrql);
3445
3446 if (Irp)
3447 {
3448 USBH_HubCancelIdleIrp(HubExtension, Irp);
3449 }
3450
3451 DbgBreakPoint();
3452 USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED);
3453 }
3454 else
3455 {
3456 PowerState.DeviceState = HubExtension->DeviceWake;
3457
3458 KeWaitForSingleObject(&HubExtension->IdleSemaphore,
3459 Executive,
3460 KernelMode,
3461 FALSE,
3462 NULL);
3463
3464 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
3465 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE;
3466
3467 KeInitializeEvent(&Event, NotificationEvent, FALSE);
3468
3469 DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n",
3470 HubExtension->LowerPDO);
3471
3472 DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n",
3473 PowerState.DeviceState);
3474
3475 Status = PoRequestPowerIrp(HubExtension->LowerPDO,
3476 IRP_MN_SET_POWER,
3477 PowerState,
3478 USBH_HubSetDWakeCompletion,
3479 &Event,
3480 NULL);
3481
3482 if (Status == STATUS_PENDING)
3483 {
3484 KeWaitForSingleObject(&Event,
3485 Executive,
3486 KernelMode,
3487 FALSE,
3488 NULL);
3489 }
3490 }
3491 }
3492
3493 VOID
3494 NTAPI
3495 USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3496 IN PVOID Context)
3497 {
3498 PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext;
3499 NTSTATUS NtStatus;
3500 NTSTATUS Status;
3501 BOOLEAN IsFlush = FALSE;
3502
3503 DPRINT("USBH_CompletePortIdleIrpsWorker ... \n");
3504
3505 IdlePortContext = Context;
3506 NtStatus = IdlePortContext->Status;
3507
3508 USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
3509 &IdlePortContext->PwrList,
3510 NtStatus);
3511
3512 DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME\n");
3513 Status = STATUS_NOT_IMPLEMENTED;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush);
3514
3515 if (NT_SUCCESS(Status))
3516 {
3517 if (IsFlush)
3518 {
3519 USBH_FlushPortPwrList(HubExtension);
3520 }
3521 }
3522 }
3523
3524 VOID
3525 NTAPI
3526 USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3527 IN PVOID Context)
3528 {
3529 PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
3530
3531 DPRINT("USBH_IdleCompletePowerHubWorker ... \n");
3532
3533 if (HubExtension &&
3534 HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
3535 HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
3536 {
3537 USBH_HubSetD0(HubExtension);
3538 }
3539
3540 HubWorkItemBuffer = Context;
3541
3542 USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status);
3543
3544 }
3545
3546 NTSTATUS
3547 NTAPI
3548 USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,
3549 IN PIRP Irp,
3550 IN PVOID Context)
3551 {
3552 PUSBHUB_FDO_EXTENSION HubExtension;
3553 NTSTATUS NtStatus;
3554 PVOID IdleIrp;
3555 KIRQL Irql;
3556 NTSTATUS Status;
3557 PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
3558
3559 IoAcquireCancelSpinLock(&Irql);
3560
3561 HubExtension = Context;
3562 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3563
3564 IdleIrp = InterlockedExchangePointer((PVOID)&HubExtension->PendingIdleIrp,
3565 NULL);
3566
3567 DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp);
3568
3569 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3570 {
3571 KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
3572 }
3573
3574 IoReleaseCancelSpinLock(Irql);
3575
3576 NtStatus = Irp->IoStatus.Status;
3577
3578 DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %lX\n",
3579 NtStatus);
3580
3581 if (!NT_SUCCESS(NtStatus) &&
3582 NtStatus != STATUS_POWER_STATE_INVALID &&
3583 !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) &&
3584 !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
3585 {
3586 DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n",
3587 HubExtension->CurrentPowerState.DeviceState);
3588
3589 if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
3590 {
3591 PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer;
3592
3593 Status = USBH_AllocateWorkItem(HubExtension,
3594 &HubIoWorkItem,
3595 USBH_CompletePortIdleIrpsWorker,
3596 sizeof(USBHUB_IDLE_PORT_CONTEXT),
3597 (PVOID *)&HubWorkItemBuffer,
3598 DelayedWorkQueue);
3599
3600 if (NT_SUCCESS(Status))
3601 {
3602 HubWorkItemBuffer->Status = NtStatus;
3603
3604 USBH_HubQueuePortIdleIrps(HubExtension,
3605 &HubWorkItemBuffer->PwrList);
3606
3607 USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3608 }
3609 }
3610 else
3611 {
3612 PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
3613
3614 Status = USBH_AllocateWorkItem(HubExtension,
3615 &HubIoWorkItem,
3616 USBH_IdleCompletePowerHubWorker,
3617 sizeof(USBHUB_IDLE_HUB_CONTEXT),
3618 (PVOID *)&HubWorkItemBuffer,
3619 DelayedWorkQueue);
3620
3621 if (NT_SUCCESS(Status))
3622 {
3623 HubWorkItemBuffer->Status = NtStatus;
3624 USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3625 }
3626 }
3627 }
3628
3629 if (IdleIrp ||
3630 InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1))
3631 {
3632 DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp);
3633 IoFreeIrp(Irp);
3634 }
3635
3636 return STATUS_MORE_PROCESSING_REQUIRED;
3637 }
3638
3639 NTSTATUS
3640 NTAPI
3641 USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
3642 {
3643 NTSTATUS Status;
3644 ULONG HubFlags;
3645 PDEVICE_OBJECT LowerPDO;
3646 PIRP Irp;
3647 PIO_STACK_LOCATION IoStack;
3648 KIRQL Irql;
3649
3650 DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n",
3651 HubExtension,
3652 HubExtension->PendingIdleIrp);
3653
3654 if (HubExtension->PendingIdleIrp)
3655 {
3656 Status = STATUS_DEVICE_BUSY;
3657 KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3658 return Status;
3659 }
3660
3661 HubFlags = HubExtension->HubFlags;
3662
3663 if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
3664 HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED)
3665 {
3666 HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3667 KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3668 return STATUS_DEVICE_REMOVED;
3669 }
3670
3671 LowerPDO = HubExtension->LowerPDO;
3672
3673 HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback;
3674 HubExtension->IdleCallbackInfo.IdleContext = HubExtension;
3675
3676 Irp = IoAllocateIrp(LowerPDO->StackSize, FALSE);
3677
3678 if (!Irp)
3679 {
3680 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3681 Status = STATUS_INSUFFICIENT_RESOURCES;
3682
3683 KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3684 return Status;
3685 }
3686
3687 IoStack = IoGetNextIrpStackLocation(Irp);
3688
3689 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
3690
3691 IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO);
3692 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
3693 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo;
3694
3695 IoSetCompletionRoutine(Irp,
3696 USBH_FdoIdleNotificationRequestComplete,
3697 HubExtension,
3698 TRUE,
3699 TRUE,
3700 TRUE);
3701
3702 InterlockedIncrement(&HubExtension->PendingRequestCount);
3703 InterlockedExchange(&HubExtension->IdleRequestLock, 0);
3704
3705 HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
3706 USBHUB_FDO_FLAG_GOING_IDLE);
3707
3708 Status = IoCallDriver(HubExtension->LowerPDO, Irp);
3709
3710 IoAcquireCancelSpinLock(&Irql);
3711
3712 if (Status == STATUS_PENDING &&
3713 HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
3714 {
3715 HubExtension->PendingIdleIrp = Irp;
3716 }
3717
3718 IoReleaseCancelSpinLock(Irql);
3719
3720 KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3721
3722 return Status;
3723 }
3724
3725 VOID
3726 NTAPI
3727 USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)
3728 {
3729 PDEVICE_OBJECT PdoDevice;
3730 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3731 PUSBHUB_PORT_DATA PortData;
3732 ULONG HubFlags;
3733 ULONG Port;
3734 KIRQL Irql;
3735 BOOLEAN IsHubIdle = FALSE;
3736 BOOLEAN IsAllPortsIdle;
3737 BOOLEAN IsHubCheck = TRUE;
3738
3739 DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension);
3740
3741 return; //HACK: delete it line after fixing Power Manager!!!
3742
3743 KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3744
3745 if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK)
3746 {
3747 KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3748 return;
3749 }
3750
3751 HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3752 KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3753
3754 if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking)
3755 {
3756 KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3757 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3758 KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3759 return;
3760 }
3761
3762 HubFlags = HubExtension->HubFlags;
3763 DPRINT("USBH_CheckHubIdle: HubFlags - %lX\n", HubFlags);
3764
3765 if (!(HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) ||
3766 !(HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
3767 {
3768 goto Exit;
3769 }
3770
3771 if (HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED ||
3772 HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER ||
3773 HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
3774 HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
3775 HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED ||
3776 HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING ||
3777 HubFlags & USBHUB_FDO_FLAG_WAKEUP_START ||
3778 HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
3779 {
3780 goto Exit;
3781 }
3782
3783 if (HubExtension->ResetRequestCount)
3784 {
3785 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
3786 goto Exit;
3787 }
3788
3789 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
3790
3791 InterlockedIncrement(&HubExtension->PendingRequestCount);
3792
3793 KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3794 Executive,
3795 KernelMode,
3796 FALSE,
3797 NULL);
3798
3799 IoAcquireCancelSpinLock(&Irql);
3800
3801 IsAllPortsIdle = TRUE;
3802
3803 PortData = HubExtension->PortData;
3804
3805 for (Port = 0;
3806 Port < HubExtension->HubDescriptor->bNumberOfPorts;
3807 Port++)
3808 {
3809 PdoDevice = PortData[Port].DeviceObject;
3810
3811 if (PdoDevice)
3812 {
3813 PortExtension = PdoDevice->DeviceExtension;
3814
3815 if (!PortExtension->IdleNotificationIrp)
3816 {
3817 DPRINT("USBH_CheckHubIdle: PortExtension - %p\n",
3818 PortExtension);
3819
3820 IsAllPortsIdle = FALSE;
3821 IsHubCheck = FALSE;
3822
3823 break;
3824 }
3825 }
3826 }
3827
3828 if (IsHubCheck &&
3829 !(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST))
3830 {
3831 KeResetEvent(&HubExtension->IdleEvent);
3832 HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3833 IsHubIdle = TRUE;
3834 }
3835
3836 IoReleaseCancelSpinLock(Irql);
3837
3838 KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3839 LOW_REALTIME_PRIORITY,
3840 1,
3841 FALSE);
3842
3843 if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3844 {
3845 KeSetEvent(&HubExtension->PendingRequestEvent,
3846 EVENT_INCREMENT,
3847 FALSE);
3848 }
3849
3850 DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n",
3851 IsAllPortsIdle,
3852 IsHubIdle);
3853
3854 if (IsAllPortsIdle && IsHubIdle)
3855 {
3856 USBH_FdoSubmitIdleRequestIrp(HubExtension);
3857 }
3858
3859 Exit:
3860 KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3861 HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3862 KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3863 }
3864
3865 VOID
3866 NTAPI
3867 USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3868 IN PVOID Context)
3869 {
3870 DPRINT("USBH_CheckIdleWorker: ... \n");
3871 USBH_CheckHubIdle(HubExtension);
3872 }
3873
3874 VOID
3875 NTAPI
3876 USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)
3877 {
3878 PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
3879 NTSTATUS Status;
3880
3881 DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension);
3882
3883 Status = USBH_AllocateWorkItem(HubExtension,
3884 &HubIoWorkItem,
3885 USBH_CheckIdleWorker,
3886 0,
3887 NULL,
3888 DelayedWorkQueue);
3889
3890 DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem);
3891
3892 if (NT_SUCCESS(Status))
3893 {
3894 USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3895 }
3896 }
3897
3898 VOID
3899 NTAPI
3900 USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
3901 {
3902 PUSBHUB_FDO_EXTENSION HubExtension;
3903 ULONG State;
3904 SYSTEM_POWER_STATE SystemPowerState;
3905 PDEVICE_POWER_STATE pDeviceState;
3906
3907 DPRINT("USBH_PdoSetCapabilities ... \n");
3908
3909 HubExtension = PortExtension->HubExtension;
3910
3911 PortExtension->Capabilities.Size = 64;
3912 PortExtension->Capabilities.Version = 1;
3913
3914 PortExtension->Capabilities.Removable = 1;
3915 PortExtension->Capabilities.Address = PortExtension->PortNumber;
3916
3917 if (PortExtension->SerialNumber)
3918 {
3919 PortExtension->Capabilities.UniqueID = 1;
3920 }
3921 else
3922 {
3923 PortExtension->Capabilities.UniqueID = 0;
3924 }
3925
3926 PortExtension->Capabilities.RawDeviceOK = 0;
3927
3928 RtlCopyMemory(PortExtension->Capabilities.DeviceState,
3929 HubExtension->DeviceState,
3930 (PowerSystemMaximum + 2) * sizeof(POWER_STATE));
3931
3932 PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0;
3933
3934 if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP)
3935 {
3936 PortExtension->Capabilities.DeviceWake = PowerDeviceD2;
3937
3938 PortExtension->Capabilities.DeviceD1 = 1;
3939 PortExtension->Capabilities.DeviceD2 = 1;
3940
3941 PortExtension->Capabilities.WakeFromD0 = 1;
3942 PortExtension->Capabilities.WakeFromD1 = 1;
3943 PortExtension->Capabilities.WakeFromD2 = 1;
3944
3945 pDeviceState = &PortExtension->Capabilities.DeviceState[2];
3946
3947 for (State = 2; State <= 5; State++)
3948 {
3949 SystemPowerState = State;
3950
3951 if (PortExtension->Capabilities.SystemWake < SystemPowerState)
3952 {
3953 *pDeviceState = PowerDeviceD3;
3954 }
3955 else
3956 {
3957 *pDeviceState = PowerDeviceD2;
3958 }
3959
3960 ++pDeviceState;
3961 }
3962 }
3963 else
3964 {
3965 PortExtension->Capabilities.DeviceWake = PowerDeviceD0;
3966 PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3;
3967 PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3;
3968 PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3;
3969 PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3;
3970 }
3971 }
3972
3973 NTSTATUS
3974 NTAPI
3975 USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
3976 {
3977 PUSB_INTERFACE_DESCRIPTOR Pid;
3978 PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
3979 NTSTATUS Status;
3980
3981 DPRINT("USBH_ProcessDeviceInformation ... \n");
3982
3983 ConfigDescriptor = NULL;
3984
3985 RtlZeroMemory(&PortExtension->InterfaceDescriptor,
3986 sizeof(PortExtension->InterfaceDescriptor));
3987
3988 PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE;
3989
3990 Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice,
3991 &ConfigDescriptor);
3992
3993 if (!NT_SUCCESS(Status))
3994 {
3995 if (ConfigDescriptor)
3996 {
3997 ExFreePool(ConfigDescriptor);
3998 }
3999
4000 return Status;
4001 }
4002
4003 PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP;
4004
4005 if (ConfigDescriptor->bmAttributes & 0x20)
4006 {
4007 /* device configuration supports remote wakeup */
4008 PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP;
4009 }
4010
4011 USBHUB_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor);
4012 USBHUB_DumpingConfiguration(ConfigDescriptor);
4013
4014 DPRINT_PNP("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n",
4015 PortExtension->DeviceDescriptor.bDeviceClass,
4016 PortExtension->DeviceDescriptor.bDeviceSubClass,
4017 PortExtension->DeviceDescriptor.bDeviceProtocol);
4018
4019 DPRINT_PNP("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n",
4020 PortExtension->DeviceDescriptor.bNumConfigurations,
4021 ConfigDescriptor->bNumInterfaces);
4022
4023
4024 /* Enumeration of USB Composite Devices (msdn):
4025 1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
4026 or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol)
4027 fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively,
4028 as explained in USB Interface Association Descriptor.
4029 2) The device must have multiple interfaces
4030 3) The device must have a single configuration.
4031 */
4032
4033 if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) ||
4034 (PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_MISCELLANEOUS &&
4035 PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 &&
4036 PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) &&
4037 (ConfigDescriptor->bNumInterfaces > 1) &&
4038 (PortExtension->DeviceDescriptor.bNumConfigurations < 2))
4039 {
4040 DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n");
4041
4042 PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE;
4043
4044 if (ConfigDescriptor)
4045 {
4046 ExFreePool(ConfigDescriptor);
4047 }
4048
4049 return Status;
4050 }
4051
4052 Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor,
4053 ConfigDescriptor,
4054 -1,
4055 -1,
4056 -1,
4057 -1,
4058 -1);
4059 if (Pid)
4060 {
4061 RtlCopyMemory(&PortExtension->InterfaceDescriptor,
4062 Pid,
4063 sizeof(PortExtension->InterfaceDescriptor));
4064
4065 if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB)
4066 {
4067 PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE |
4068 USBHUB_PDO_FLAG_REMOTE_WAKEUP);
4069 }
4070 }
4071 else
4072 {
4073 Status = STATUS_UNSUCCESSFUL;
4074 }
4075
4076 if (ConfigDescriptor)
4077 {
4078 ExFreePool(ConfigDescriptor);
4079 }
4080
4081 return Status;
4082 }
4083
4084 BOOLEAN
4085 NTAPI
4086 USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,
4087 IN USHORT idVendor,
4088 IN USHORT idProduct,
4089 IN PVOID SerialNumber,
4090 IN USHORT SN_DescriptorLength)
4091 {
4092 PDEVICE_OBJECT PortDevice;
4093 PUSBHUB_PORT_PDO_EXTENSION PortExtension;
4094 ULONG Port;
4095 SIZE_T NumberBytes;
4096
4097 DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n",
4098 idVendor,
4099 idProduct);
4100
4101 if (!HubExtension->HubDescriptor->bNumberOfPorts)
4102 {
4103 return TRUE;
4104 }
4105
4106 for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
4107 {
4108 PortDevice = HubExtension->PortData[Port].DeviceObject;
4109
4110 if (PortDevice)
4111 {
4112 PortExtension = PortDevice->DeviceExtension;