xref: /reactos/drivers/usb/usbhub/usbhub.c (revision 67b3b73d)
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
USBH_Wait(IN ULONG Milliseconds)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
USBH_GetConfigValue(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)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
USBH_CompleteIrp(IN PIRP Irp,IN NTSTATUS CompleteStatus)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
USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
IsBitSet(IN PUCHAR BitMapAddress,IN USHORT Bit)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
PdoExt(IN PDEVICE_OBJECT DeviceObject)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
USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject,IN ULONG FailReason)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
USBH_UrbTimeoutDPC(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)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
USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject,IN PCWSTR ValueName,IN PVOID Data,IN ULONG DataSize,IN ULONG Type,IN ULONG DevInstKeyType)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
USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject,IN PURB Urb)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
USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice,IN PURB Urb)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
USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID TransferBuffer,IN ULONG BufferLen,IN BOOLEAN IsDeviceToHost,IN USHORT Function,IN BM_REQUEST_TYPE RequestType,IN UCHAR Request,IN USHORT RequestValue,IN USHORT RequestIndex)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
USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port)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
USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_DEVICE_HANDLE DeviceHandle,OUT USB_DEVICE_TYPE * OutDeviceType)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
USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer)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
USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension)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
USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject,IN OUT PDEVICE_OBJECT * OutPdo1,IN OUT PDEVICE_OBJECT * OutPdo2)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
USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject,IN OUT PULONG OutHubCount)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
USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject)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
USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject,IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor)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
USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,IN ULONG NumberOfBytes,IN PULONG OutLength)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
USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,IN PUSB_CONFIGURATION_DESCRIPTOR * OutDescriptor)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
USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension)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
USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject,IN UCHAR Index,IN USHORT LanguageId,IN PUSB_STRING_DESCRIPTOR Descriptor,IN ULONG NumberOfBytes,IN PULONG OutLength,IN BOOLEAN IsValidateLength)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
USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject,IN PUSHORT OutStatus,IN USHORT Function,IN USHORT RequestIndex)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
USBH_SyncGetHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_HUB_STATUS_AND_CHANGE HubStatus,IN ULONG Length)1363 USBH_SyncGetHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1364                       IN PUSB_HUB_STATUS_AND_CHANGE HubStatus,
1365                       IN ULONG Length)
1366 {
1367     BM_REQUEST_TYPE RequestType;
1368 
1369     DPRINT("USBH_SyncGetHubStatus\n");
1370 
1371     RequestType.B = 0;
1372     RequestType.Recipient = BMREQUEST_TO_DEVICE;
1373     RequestType.Type = BMREQUEST_CLASS;
1374     RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1375 
1376     return USBH_Transact(HubExtension,
1377                          HubStatus,
1378                          Length,
1379                          BMREQUEST_DEVICE_TO_HOST,
1380                          URB_FUNCTION_CLASS_DEVICE,
1381                          RequestType,
1382                          USB_REQUEST_GET_STATUS,
1383                          0,
1384                          0);
1385 }
1386 
1387 NTSTATUS
1388 NTAPI
USBH_SyncClearHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT RequestValue)1389 USBH_SyncClearHubStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1390                         IN USHORT RequestValue)
1391 {
1392     BM_REQUEST_TYPE RequestType;
1393 
1394     DPRINT("USBH_SyncClearHubStatus: RequestValue - %x\n", RequestValue);
1395 
1396     RequestType.B = 0;
1397     RequestType.Recipient = BMREQUEST_TO_DEVICE;
1398     RequestType.Type = BMREQUEST_CLASS;
1399     RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1400 
1401     return USBH_Transact(HubExtension,
1402                          NULL,
1403                          0,
1404                          BMREQUEST_HOST_TO_DEVICE,
1405                          URB_FUNCTION_CLASS_DEVICE,
1406                          RequestType,
1407                          USB_REQUEST_CLEAR_FEATURE,
1408                          RequestValue,
1409                          0);
1410 }
1411 
1412 NTSTATUS
1413 NTAPI
USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN PUSB_PORT_STATUS_AND_CHANGE PortStatus,IN ULONG Length)1414 USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1415                        IN USHORT Port,
1416                        IN PUSB_PORT_STATUS_AND_CHANGE PortStatus,
1417                        IN ULONG Length)
1418 {
1419     BM_REQUEST_TYPE RequestType;
1420 
1421     DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port);
1422 
1423     RequestType.B = 0;
1424     RequestType.Recipient = BMREQUEST_TO_OTHER;
1425     RequestType.Type = BMREQUEST_CLASS;
1426     RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1427 
1428     return USBH_Transact(HubExtension,
1429                          PortStatus,
1430                          Length,
1431                          BMREQUEST_DEVICE_TO_HOST,
1432                          URB_FUNCTION_CLASS_OTHER,
1433                          RequestType,
1434                          USB_REQUEST_GET_STATUS,
1435                          0,
1436                          Port);
1437 }
1438 
1439 
1440 NTSTATUS
1441 NTAPI
USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN USHORT RequestValue)1442 USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1443                          IN USHORT Port,
1444                          IN USHORT RequestValue)
1445 {
1446     BM_REQUEST_TYPE RequestType;
1447 
1448     DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n",
1449            Port,
1450            RequestValue);
1451 
1452     RequestType.B = 0;
1453     RequestType.Recipient = BMREQUEST_TO_OTHER;
1454     RequestType.Type = BMREQUEST_CLASS;
1455     RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1456 
1457     return USBH_Transact(HubExtension,
1458                          NULL,
1459                          0,
1460                          BMREQUEST_HOST_TO_DEVICE,
1461                          URB_FUNCTION_CLASS_OTHER,
1462                          RequestType,
1463                          USB_REQUEST_CLEAR_FEATURE,
1464                          RequestValue,
1465                          Port);
1466 }
1467 
1468 NTSTATUS
1469 NTAPI
USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN BOOLEAN IsWait)1470 USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
1471                      IN USHORT Port,
1472                      IN BOOLEAN IsWait)
1473 {
1474     PUSBHUB_PORT_DATA PortData;
1475     PUSB_HUB_DESCRIPTOR HubDescriptor;
1476     NTSTATUS Status = STATUS_SUCCESS;
1477     BM_REQUEST_TYPE RequestType;
1478     PUSB_PORT_STATUS_AND_CHANGE PortStatus;
1479 
1480     DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait);
1481 
1482     ASSERT(Port > 0);
1483     PortData = &HubExtension->PortData[Port - 1];
1484     PortStatus = &PortData->PortStatus;
1485 
1486     if (PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus == 1)
1487     {
1488         return Status;
1489     }
1490 
1491     RequestType.B = 0;
1492     RequestType.Recipient = BMREQUEST_TO_DEVICE;
1493     RequestType.Type = BMREQUEST_CLASS;
1494     RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1495 
1496     Status = USBH_Transact(HubExtension,
1497                            NULL,
1498                            0,
1499                            BMREQUEST_HOST_TO_DEVICE,
1500                            URB_FUNCTION_CLASS_OTHER,
1501                            RequestType,
1502                            USB_REQUEST_SET_FEATURE,
1503                            USBHUB_FEATURE_PORT_POWER,
1504                            Port);
1505 
1506     if (NT_SUCCESS(Status))
1507     {
1508         if (IsWait)
1509         {
1510             HubDescriptor = HubExtension->HubDescriptor;
1511             USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
1512         }
1513 
1514         PortStatus->PortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
1515     }
1516 
1517     return Status;
1518 }
1519 
1520 NTSTATUS
1521 NTAPI
USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)1522 USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)
1523 {
1524     PUSB_HUB_DESCRIPTOR HubDescriptor;
1525     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1526     USHORT Port;
1527     UCHAR NumberOfPorts;
1528 
1529     DPRINT("USBH_SyncPowerOnPorts: ... \n");
1530 
1531     HubDescriptor = HubExtension->HubDescriptor;
1532     NumberOfPorts = HubDescriptor->bNumberOfPorts;
1533 
1534     for (Port = 1; Port <= NumberOfPorts; ++Port)
1535     {
1536         Status = USBH_SyncPowerOnPort(HubExtension, Port, 0);
1537 
1538         if (!NT_SUCCESS(Status))
1539         {
1540             DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %lX\n",
1541                     Status);
1542             break;
1543         }
1544     }
1545 
1546     USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
1547 
1548     return Status;
1549 }
1550 
1551 NTSTATUS
1552 NTAPI
USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port)1553 USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,
1554                      IN USHORT Port)
1555 {
1556     PUSBHUB_PORT_DATA PortData;
1557     NTSTATUS Status;
1558     BM_REQUEST_TYPE RequestType;
1559 
1560     DPRINT("USBH_SyncDisablePort ... \n");
1561 
1562     PortData = &HubExtension->PortData[Port - 1];
1563 
1564     RequestType.B = 0;
1565     RequestType.Recipient = BMREQUEST_TO_DEVICE;
1566     RequestType.Type = BMREQUEST_CLASS;
1567     RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1568 
1569     Status = USBH_Transact(HubExtension,
1570                            NULL,
1571                            0,
1572                            BMREQUEST_HOST_TO_DEVICE,
1573                            URB_FUNCTION_CLASS_OTHER,
1574                            RequestType,
1575                            USB_REQUEST_CLEAR_FEATURE,
1576                            USBHUB_FEATURE_PORT_ENABLE,
1577                            Port);
1578 
1579     if (NT_SUCCESS(Status))
1580     {
1581         PortData->PortStatus.PortStatus.Usb20PortStatus.PortEnabledDisabled = 0;
1582     }
1583 
1584     return Status;
1585 }
1586 
1587 BOOLEAN
1588 NTAPI
USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)1589 USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,
1590                      IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)
1591 {
1592     BOOLEAN Result;
1593     USHORT UsbStatus;
1594     NTSTATUS Status;
1595 
1596     DPRINT("USBH_HubIsBusPowered: ... \n");
1597 
1598     Status = USBH_SyncGetStatus(DeviceObject,
1599                                 &UsbStatus,
1600                                 URB_FUNCTION_GET_STATUS_FROM_DEVICE,
1601                                 0);
1602 
1603     if (!NT_SUCCESS(Status))
1604     {
1605         Result = (HubConfigDescriptor->bmAttributes & USB_CONFIG_POWERED_MASK)
1606                                                    == USB_CONFIG_BUS_POWERED;
1607     }
1608     else
1609     {
1610         Result = (UsbStatus & USB_GETSTATUS_SELF_POWERED) == 0;
1611     }
1612 
1613     return Result;
1614 }
1615 
1616 NTSTATUS
1617 NTAPI
USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)1618 USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,
1619                                        IN PIRP Irp,
1620                                        IN PVOID Context)
1621 {
1622     PUSBHUB_FDO_EXTENSION HubExtension;
1623     PVOID Event;
1624     USHORT Port;
1625 
1626     HubExtension = Context;
1627 
1628     DPRINT_SCE("USBH_ChangeIndicationAckChangeComplete: ... \n");
1629 
1630     ASSERT(HubExtension->Port > 0);
1631     Port = HubExtension->Port - 1;
1632 
1633     HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus;
1634 
1635     Event = InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
1636                                        NULL);
1637 
1638     if (Event)
1639     {
1640         KeSetEvent(Event, EVENT_INCREMENT, FALSE);
1641     }
1642 
1643     USBH_SubmitStatusChangeTransfer(HubExtension);
1644 
1645     if (!InterlockedDecrement(&HubExtension->ResetRequestCount))
1646     {
1647         KeSetEvent(&HubExtension->ResetEvent,
1648                    EVENT_INCREMENT,
1649                    FALSE);
1650     }
1651 
1652     return STATUS_MORE_PROCESSING_REQUIRED;
1653 }
1654 
1655 NTSTATUS
1656 NTAPI
USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp,IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,IN USHORT Port,IN USHORT RequestValue)1657 USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1658                                IN PIRP Irp,
1659                                IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
1660                                IN USHORT Port,
1661                                IN USHORT RequestValue)
1662 {
1663     PIO_STACK_LOCATION IoStack;
1664     BM_REQUEST_TYPE RequestType;
1665 
1666     DPRINT_SCE("USBH_ChangeIndicationAckChange: ... \n");
1667 
1668     Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
1669     Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
1670     Urb->Hdr.UsbdDeviceHandle = NULL;
1671 
1672     Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
1673     Urb->TransferBufferLength = 0;
1674     Urb->TransferBuffer = NULL;
1675     Urb->TransferBufferMDL = NULL;
1676     Urb->UrbLink = NULL;
1677 
1678     RequestType.B = 0;
1679     RequestType.Recipient = BMREQUEST_TO_OTHER;
1680     RequestType.Type = BMREQUEST_CLASS;
1681     RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1682 
1683     Urb->RequestTypeReservedBits = RequestType.B;
1684     Urb->Request = USB_REQUEST_CLEAR_FEATURE;
1685     Urb->Index = Port;
1686     Urb->Value = RequestValue;
1687 
1688     IoInitializeIrp(Irp,
1689                     IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
1690                     HubExtension->LowerDevice->StackSize);
1691 
1692     IoStack = IoGetNextIrpStackLocation(Irp);
1693 
1694     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1695     IoStack->Parameters.Others.Argument1 = Urb;
1696     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
1697 
1698     IoSetCompletionRoutine(Irp,
1699                            USBH_ChangeIndicationAckChangeComplete,
1700                            HubExtension,
1701                            TRUE,
1702                            TRUE,
1703                            TRUE);
1704 
1705     return IoCallDriver(HubExtension->LowerDevice, Irp);
1706 }
1707 
1708 NTSTATUS
1709 NTAPI
USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)1710 USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,
1711                                    IN PIRP Irp,
1712                                    IN PVOID Context)
1713 {
1714     PUSBHUB_FDO_EXTENSION HubExtension;
1715     PUSBHUB_IO_WORK_ITEM WorkItem;
1716     USHORT RequestValue;
1717 
1718     HubExtension = Context;
1719 
1720     DPRINT_SCE("USBH_ChangeIndicationProcessChange: PortStatus - %lX\n",
1721                HubExtension->PortStatus.AsUlong32);
1722 
1723     if ((NT_SUCCESS(Irp->IoStatus.Status) ||
1724         USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) &&
1725         (HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange ||
1726          HubExtension->PortStatus.PortChange.Usb20PortChange.PortEnableDisableChange))
1727     {
1728         if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
1729         {
1730             KeSetEvent(&HubExtension->PendingRequestEvent,
1731                        EVENT_INCREMENT,
1732                        FALSE);
1733         }
1734 
1735         USBH_FreeWorkItem(HubExtension->WorkItemToQueue);
1736 
1737         HubExtension->WorkItemToQueue = NULL;
1738 
1739         if (HubExtension->PortStatus.PortChange.Usb20PortChange.ResetChange)
1740         {
1741            RequestValue = USBHUB_FEATURE_C_PORT_RESET;
1742         }
1743         else
1744         {
1745             RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
1746         }
1747 
1748         USBH_ChangeIndicationAckChange(HubExtension,
1749                                        HubExtension->ResetPortIrp,
1750                                        &HubExtension->SCEWorkerUrb,
1751                                        HubExtension->Port,
1752                                        RequestValue);
1753     }
1754     else
1755     {
1756         ASSERT(HubExtension->WorkItemToQueue != NULL);
1757 
1758         WorkItem = HubExtension->WorkItemToQueue;
1759         HubExtension->WorkItemToQueue = NULL;
1760 
1761         USBH_QueueWorkItem(HubExtension, WorkItem);
1762     }
1763 
1764     return STATUS_MORE_PROCESSING_REQUIRED;
1765 }
1766 
1767 NTSTATUS
1768 NTAPI
USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp,IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,IN USHORT Port)1769 USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1770                                  IN PIRP Irp,
1771                                  IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
1772                                  IN USHORT Port)
1773 {
1774     PUSBHUB_IO_WORK_ITEM WorkItem;
1775     NTSTATUS Status;
1776     PIO_STACK_LOCATION IoStack;
1777     BM_REQUEST_TYPE RequestType;
1778 
1779     DPRINT_SCE("USBH_ChangeIndicationQueryChange: Port - %x\n", Port);
1780 
1781     InterlockedIncrement(&HubExtension->PendingRequestCount);
1782 
1783     if (!Port)
1784     {
1785         ASSERT(HubExtension->WorkItemToQueue != NULL);
1786 
1787         WorkItem = HubExtension->WorkItemToQueue;
1788         HubExtension->WorkItemToQueue = NULL;
1789 
1790         USBH_QueueWorkItem(HubExtension, WorkItem);
1791 
1792         return STATUS_SUCCESS;
1793     }
1794 
1795     Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
1796     Urb->Hdr.UsbdDeviceHandle = NULL;
1797     Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
1798 
1799     Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
1800     Urb->TransferBuffer = &HubExtension->PortStatus;
1801     Urb->TransferBufferLength = sizeof(HubExtension->PortStatus);
1802     Urb->TransferBufferMDL = NULL;
1803     Urb->UrbLink = NULL;
1804 
1805     RequestType.B = 0;
1806     RequestType.Recipient = BMREQUEST_TO_OTHER;
1807     RequestType.Type = BMREQUEST_CLASS;
1808     RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1809 
1810     Urb->RequestTypeReservedBits = RequestType.B;
1811     Urb->Request = USB_REQUEST_GET_STATUS;
1812     Urb->Value = 0;
1813     Urb->Index = Port;
1814 
1815     HubExtension->Port = Port;
1816 
1817     IoInitializeIrp(Irp,
1818                     IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
1819                     HubExtension->LowerDevice->StackSize);
1820 
1821     IoStack = IoGetNextIrpStackLocation(Irp);
1822 
1823     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1824     IoStack->Parameters.Others.Argument1 = Urb;
1825     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
1826 
1827     IoSetCompletionRoutine(Irp,
1828                            USBH_ChangeIndicationProcessChange,
1829                            HubExtension,
1830                            TRUE,
1831                            TRUE,
1832                            TRUE);
1833 
1834     Status = IoCallDriver(HubExtension->LowerDevice, Irp);
1835 
1836     return Status;
1837 }
1838 
1839 VOID
1840 NTAPI
USBH_ProcessHubStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_HUB_STATUS_AND_CHANGE HubStatus)1841 USBH_ProcessHubStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1842                            IN PUSB_HUB_STATUS_AND_CHANGE HubStatus)
1843 {
1844     USB_HUB_CHANGE HubStatusChange;
1845 
1846     DPRINT_SCE("USBH_ProcessHubStateChange: HubStatus - %lx\n", HubStatus->AsUlong32);
1847 
1848     HubStatusChange = HubStatus->HubChange;
1849 
1850     if (HubStatusChange.LocalPowerChange)
1851     {
1852         DPRINT1("USBH_ProcessHubStateChange: LocalPowerChange\n");
1853         USBH_SyncClearHubStatus(HubExtension,
1854                                 USBHUB_FEATURE_C_HUB_LOCAL_POWER);
1855     }
1856     else if (HubStatusChange.OverCurrentChange)
1857     {
1858         USBH_SyncClearHubStatus(HubExtension,
1859                                 USBHUB_FEATURE_C_HUB_OVER_CURRENT);
1860         if (HubStatus->HubStatus.OverCurrent)
1861         {
1862             DPRINT1("USBH_ProcessHubStateChange: OverCurrent UNIMPLEMENTED. FIXME\n");
1863             DbgBreakPoint();
1864         }
1865     }
1866 }
1867 
1868 VOID
1869 NTAPI
USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)1870 USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
1871                             IN USHORT Port,
1872                             IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)
1873 {
1874     PUSBHUB_PORT_DATA PortData;
1875     USB_20_PORT_CHANGE PortStatusChange;
1876     PDEVICE_OBJECT PortDevice;
1877     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
1878     PVOID SerialNumber;
1879     PVOID DeviceHandle;
1880     USHORT RequestValue;
1881     KIRQL Irql;
1882 
1883     DPRINT_SCE("USBH_ProcessPortStateChange ... \n");
1884 
1885     ASSERT(Port > 0);
1886     PortData = &HubExtension->PortData[Port - 1];
1887 
1888     PortStatusChange = PortStatus->PortChange.Usb20PortChange;
1889 
1890     if (PortStatusChange.ConnectStatusChange)
1891     {
1892         PortData->PortStatus = *PortStatus;
1893 
1894         USBH_SyncClearPortStatus(HubExtension,
1895                                  Port,
1896                                  USBHUB_FEATURE_C_PORT_CONNECTION);
1897 
1898         PortData = &HubExtension->PortData[Port - 1];
1899 
1900         PortDevice = PortData->DeviceObject;
1901 
1902         if (!PortDevice)
1903         {
1904             IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1905             return;
1906         }
1907 
1908         PortExtension = PortDevice->DeviceExtension;
1909 
1910         if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
1911         {
1912             return;
1913         }
1914 
1915         KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql);
1916 
1917         if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
1918         {
1919             KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
1920             IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1921             return;
1922         }
1923 
1924         PortData->DeviceObject = NULL;
1925         PortData->ConnectionStatus = NoDeviceConnected;
1926 
1927         HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING;
1928 
1929         InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink);
1930 
1931         KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
1932 
1933         SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
1934                                                   NULL);
1935 
1936         if (SerialNumber)
1937         {
1938             ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
1939         }
1940 
1941         DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
1942                                                   NULL);
1943 
1944         if (DeviceHandle)
1945         {
1946             USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
1947             USBH_SyncDisablePort(HubExtension, Port);
1948         }
1949 
1950         IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
1951     }
1952     else if (PortStatusChange.PortEnableDisableChange)
1953     {
1954         RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
1955         PortData->PortStatus = *PortStatus;
1956         USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
1957         return;
1958     }
1959     else if (PortStatusChange.SuspendChange)
1960     {
1961         DPRINT1("USBH_ProcessPortStateChange: SuspendChange UNIMPLEMENTED. FIXME\n");
1962         DbgBreakPoint();
1963     }
1964     else if (PortStatusChange.OverCurrentIndicatorChange)
1965     {
1966         DPRINT1("USBH_ProcessPortStateChange: OverCurrentIndicatorChange UNIMPLEMENTED. FIXME\n");
1967         DbgBreakPoint();
1968     }
1969     else if (PortStatusChange.ResetChange)
1970     {
1971         RequestValue = USBHUB_FEATURE_C_PORT_RESET;
1972         PortData->PortStatus = *PortStatus;
1973         USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
1974     }
1975 }
1976 
1977 NTSTATUS
1978 NTAPI
USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PULONG PortStatus)1979 USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
1980                    IN PULONG PortStatus)
1981 {
1982     PIRP Irp;
1983     PIO_STACK_LOCATION IoStack;
1984     NTSTATUS Status;
1985     KEVENT Event;
1986     IO_STATUS_BLOCK IoStatusBlock;
1987 
1988     DPRINT("USBH_GetPortStatus ... \n");
1989 
1990     *PortStatus = 0;
1991 
1992     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1993 
1994     Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
1995                                         HubExtension->LowerDevice,
1996                                         NULL,
1997                                         0,
1998                                         NULL,
1999                                         0,
2000                                         TRUE,
2001                                         &Event,
2002                                         &IoStatusBlock);
2003 
2004     if (!Irp)
2005     {
2006         return STATUS_INSUFFICIENT_RESOURCES;
2007     }
2008 
2009     IoStack = IoGetNextIrpStackLocation(Irp);
2010     IoStack->Parameters.Others.Argument1 = PortStatus;
2011 
2012     Status = IoCallDriver(HubExtension->LowerDevice, Irp);
2013 
2014     if (Status == STATUS_PENDING)
2015     {
2016         KeWaitForSingleObject(&Event,
2017                               Suspended,
2018                               KernelMode,
2019                               FALSE,
2020                               NULL);
2021     }
2022     else
2023     {
2024         IoStatusBlock.Status = Status;
2025     }
2026 
2027     return IoStatusBlock.Status;
2028 }
2029 
2030 NTSTATUS
2031 NTAPI
USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)2032 USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)
2033 {
2034     PIRP Irp;
2035     NTSTATUS Status;
2036     KEVENT Event;
2037     IO_STATUS_BLOCK IoStatusBlock;
2038 
2039     DPRINT("USBH_EnableParentPort ... \n");
2040 
2041     KeInitializeEvent(&Event, NotificationEvent, FALSE);
2042 
2043     Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT,
2044                                         HubExtension->LowerDevice,
2045                                         NULL,
2046                                         0,
2047                                         NULL,
2048                                         0,
2049                                         TRUE,
2050                                         &Event,
2051                                         &IoStatusBlock);
2052 
2053     if (!Irp)
2054     {
2055         return STATUS_INSUFFICIENT_RESOURCES;
2056     }
2057 
2058     Status = IoCallDriver(HubExtension->LowerDevice, Irp);
2059 
2060     if (Status == STATUS_PENDING)
2061     {
2062         KeWaitForSingleObject(&Event,
2063                               Suspended,
2064                               KernelMode,
2065                               FALSE,
2066                               NULL);
2067     }
2068     else
2069     {
2070         IoStatusBlock.Status = Status;
2071     }
2072 
2073     return IoStatusBlock.Status;
2074 }
2075 
2076 NTSTATUS
2077 NTAPI
USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)2078 USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
2079 {
2080     struct _URB_PIPE_REQUEST * Urb;
2081     NTSTATUS Status;
2082 
2083     DPRINT("USBH_ResetInterruptPipe ... \n");
2084 
2085     Urb = ExAllocatePoolWithTag(NonPagedPool,
2086                                 sizeof(struct _URB_PIPE_REQUEST),
2087                                 USB_HUB_TAG);
2088 
2089     if (Urb)
2090     {
2091         RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
2092 
2093         Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
2094         Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
2095         Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
2096 
2097         Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
2098                                        (PURB)Urb);
2099 
2100         ExFreePoolWithTag(Urb, USB_HUB_TAG);
2101     }
2102     else
2103     {
2104         Status = STATUS_INSUFFICIENT_RESOURCES;
2105     }
2106 
2107     if (NT_SUCCESS(Status))
2108     {
2109         HubExtension->RequestErrors = 0;
2110     }
2111 
2112     return Status;
2113 }
2114 
2115 NTSTATUS
2116 NTAPI
USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)2117 USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)
2118 {
2119     NTSTATUS Status;
2120     ULONG PortStatusFlags = 0;
2121 
2122     DPRINT("USBH_ResetHub: ... \n");
2123 
2124     Status = USBH_GetPortStatus(HubExtension, &PortStatusFlags);
2125 
2126     if (!NT_SUCCESS(Status))
2127     {
2128         return Status;
2129     }
2130 
2131     if (!(PortStatusFlags & USBD_PORT_ENABLED))
2132     {
2133         if (PortStatusFlags & USBD_PORT_CONNECTED)
2134         {
2135             USBH_EnableParentPort(HubExtension);
2136         }
2137     }
2138 
2139     Status = USBH_ResetInterruptPipe(HubExtension);
2140 
2141     return Status;
2142 }
2143 
2144 VOID
2145 NTAPI
USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)2146 USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
2147                             IN PVOID Context)
2148 {
2149     PUSBHUB_FDO_EXTENSION LowerHubExtension;
2150     PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension;
2151     PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem;
2152     USB_PORT_STATUS_AND_CHANGE PortStatus;
2153     USB_HUB_STATUS_AND_CHANGE HubStatus;
2154     NTSTATUS Status;
2155     USHORT Port = 0;
2156 
2157     DPRINT_SCE("USBH_ChangeIndicationWorker ... \n");
2158 
2159     WorkItem = Context;
2160 
2161     KeWaitForSingleObject(&HubExtension->HubSemaphore,
2162                           Executive,
2163                           KernelMode,
2164                           FALSE,
2165                           NULL);
2166 
2167     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)
2168     {
2169         KeSetEvent(&HubExtension->StatusChangeEvent,
2170                    EVENT_INCREMENT,
2171                    FALSE);
2172 
2173         goto Exit;
2174     }
2175 
2176     if (!HubExtension->RequestErrors)
2177     {
2178         goto Enum;
2179     }
2180 
2181     DPRINT_SCE("USBH_ChangeIndicationWorker: RequestErrors - %x\n",
2182                HubExtension->RequestErrors);
2183 
2184     if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
2185     {
2186         goto Enum;
2187     }
2188 
2189     LowerPortExtension = HubExtension->LowerPDO->DeviceExtension;
2190 
2191     if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2)
2192     {
2193         goto Enum;
2194     }
2195 
2196     LowerHubExtension = LowerPortExtension->HubExtension;
2197 
2198     if (!LowerHubExtension)
2199     {
2200         goto Enum;
2201     }
2202 
2203     Status = USBH_SyncGetPortStatus(LowerHubExtension,
2204                                     LowerPortExtension->PortNumber,
2205                                     &PortStatus,
2206                                     sizeof(USB_PORT_STATUS_AND_CHANGE));
2207 
2208     if (!NT_SUCCESS(Status) ||
2209         !PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus)
2210     {
2211         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
2212 
2213         KeSetEvent(&HubExtension->StatusChangeEvent,
2214                    EVENT_INCREMENT,
2215                    FALSE);
2216 
2217         goto Exit;
2218     }
2219 
2220     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING))
2221     {
2222         HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING;
2223 
2224         DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME\n");
2225         DbgBreakPoint();
2226 
2227         goto Exit;
2228     }
2229 
2230 Enum:
2231 
2232     if (WorkItem->IsRequestErrors)
2233     {
2234         USBH_ResetHub(HubExtension);
2235     }
2236     else
2237     {
2238         for (Port = 0;
2239              Port < HubExtension->HubDescriptor->bNumberOfPorts;
2240              Port++)
2241         {
2242             if (IsBitSet((PUCHAR)(WorkItem + 1), Port))
2243             {
2244                 break;
2245             }
2246         }
2247 
2248         if (Port)
2249         {
2250             Status = USBH_SyncGetPortStatus(HubExtension,
2251                                             Port,
2252                                             &PortStatus,
2253                                             sizeof(PortStatus));
2254         }
2255         else
2256         {
2257             Status = USBH_SyncGetHubStatus(HubExtension,
2258                                            &HubStatus,
2259                                            sizeof(HubStatus));
2260         }
2261 
2262         if (NT_SUCCESS(Status))
2263         {
2264             if (Port)
2265             {
2266                 USBH_ProcessPortStateChange(HubExtension,
2267                                             Port,
2268                                             &PortStatus);
2269             }
2270             else
2271             {
2272                 USBH_ProcessHubStateChange(HubExtension,
2273                                            &HubStatus);
2274             }
2275         }
2276         else
2277         {
2278             HubExtension->RequestErrors++;
2279 
2280             if (HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS)
2281             {
2282                 HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
2283                 goto Exit;
2284             }
2285         }
2286     }
2287 
2288     USBH_SubmitStatusChangeTransfer(HubExtension);
2289 
2290 Exit:
2291 
2292     KeReleaseSemaphore(&HubExtension->HubSemaphore,
2293                        LOW_REALTIME_PRIORITY,
2294                        1,
2295                        FALSE);
2296 
2297     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
2298     {
2299         KeSetEvent(&HubExtension->PendingRequestEvent,
2300                    EVENT_INCREMENT,
2301                    FALSE);
2302     }
2303 
2304     if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount))
2305     {
2306         KeSetEvent(&HubExtension->ResetEvent,
2307                    EVENT_INCREMENT,
2308                    FALSE);
2309 
2310         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE)
2311         {
2312             USBH_CheckHubIdle(HubExtension);
2313         }
2314     }
2315 }
2316 
2317 NTSTATUS
2318 NTAPI
USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)2319 USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,
2320                       IN PIRP Irp,
2321                       IN PVOID Context)
2322 {
2323     PUSBHUB_FDO_EXTENSION HubExtension;
2324     USBD_STATUS UrbStatus;
2325     BOOLEAN IsErrors = FALSE;
2326     PUSBHUB_IO_WORK_ITEM HubWorkItem;
2327     PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer;
2328     USHORT NumPorts;
2329     USHORT Port;
2330     NTSTATUS Status;
2331     PVOID Bitmap;
2332     ULONG BufferLength;
2333 
2334     HubExtension = Context;
2335     UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status;
2336 
2337     DPRINT_SCE("USBH_ChangeIndication: IrpStatus - %x, UrbStatus - %x, HubFlags - %lX\n",
2338                Irp->IoStatus.Status,
2339                UrbStatus,
2340                HubExtension->HubFlags);
2341 
2342     if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) ||
2343        (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) ||
2344        (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING))
2345     {
2346         HubExtension->RequestErrors++;
2347 
2348         IsErrors = TRUE;
2349 
2350         KeSetEvent(&HubExtension->StatusChangeEvent,
2351                    EVENT_INCREMENT,
2352                    FALSE);
2353 
2354         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
2355             HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
2356             HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS ||
2357             Irp->IoStatus.Status == STATUS_DELETE_PENDING)
2358         {
2359             DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
2360                        HubExtension->RequestErrors);
2361 
2362             return STATUS_MORE_PROCESSING_REQUIRED;
2363         }
2364 
2365         DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
2366                    HubExtension->RequestErrors);
2367     }
2368     else
2369     {
2370         HubExtension->RequestErrors = 0;
2371     }
2372 
2373     BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) +
2374                    HubExtension->SCEBitmapLength;
2375 
2376     Status = USBH_AllocateWorkItem(HubExtension,
2377                                    &HubWorkItem,
2378                                    USBH_ChangeIndicationWorker,
2379                                    BufferLength,
2380                                    (PVOID *)&HubWorkItemBuffer,
2381                                    DelayedWorkQueue);
2382 
2383     if (!NT_SUCCESS(Status))
2384     {
2385         return STATUS_MORE_PROCESSING_REQUIRED;
2386     }
2387 
2388     RtlZeroMemory(HubWorkItemBuffer, BufferLength);
2389 
2390     HubWorkItemBuffer->IsRequestErrors = FALSE;
2391 
2392     if (IsErrors)
2393     {
2394         HubWorkItemBuffer->IsRequestErrors = TRUE;
2395     }
2396 
2397     if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1)
2398     {
2399         KeClearEvent(&HubExtension->ResetEvent);
2400     }
2401 
2402     HubWorkItemBuffer->HubExtension = HubExtension;
2403 
2404     HubExtension->WorkItemToQueue = HubWorkItem;
2405 
2406     Bitmap = HubWorkItemBuffer + 1;
2407 
2408     RtlCopyMemory(Bitmap,
2409                   HubExtension->SCEBitmap,
2410                   HubExtension->SCEBitmapLength);
2411 
2412     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
2413 
2414     for (Port = 0; Port <= NumPorts; ++Port)
2415     {
2416         if (IsBitSet(Bitmap, Port))
2417         {
2418             break;
2419         }
2420     }
2421 
2422     if (Port > NumPorts)
2423     {
2424         Port = 0;
2425     }
2426 
2427     Status = USBH_ChangeIndicationQueryChange(HubExtension,
2428                                               HubExtension->ResetPortIrp,
2429                                               &HubExtension->SCEWorkerUrb,
2430                                               Port);
2431 
2432     if (NT_ERROR(Status))
2433     {
2434         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
2435     }
2436 
2437     return STATUS_MORE_PROCESSING_REQUIRED;
2438 }
2439 
2440 NTSTATUS
2441 NTAPI
USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)2442 USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)
2443 {
2444     PIRP Irp;
2445     NTSTATUS Status;
2446     struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb;
2447     PIO_STACK_LOCATION IoStack;
2448 
2449     DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n",
2450                HubExtension,
2451                HubExtension->SCEIrp);
2452 
2453     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE)
2454     {
2455         DPRINT_SCE("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE\n");
2456         DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubFlags - %lX\n",
2457                    HubExtension->HubFlags);
2458 
2459         return STATUS_INVALID_DEVICE_STATE;
2460     }
2461 
2462     Irp = HubExtension->SCEIrp;
2463 
2464     if (!Irp)
2465     {
2466         return STATUS_INVALID_DEVICE_STATE;
2467     }
2468 
2469     Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb;
2470 
2471     Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
2472     Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
2473     Urb->Hdr.UsbdDeviceHandle = NULL;
2474 
2475     Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
2476     Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
2477     Urb->TransferBuffer = HubExtension->SCEBitmap;
2478     Urb->TransferBufferLength = HubExtension->SCEBitmapLength;
2479     Urb->TransferBufferMDL = NULL;
2480     Urb->UrbLink = NULL;
2481 
2482     IoInitializeIrp(Irp,
2483                     IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
2484                     HubExtension->LowerDevice->StackSize);
2485 
2486     IoStack = IoGetNextIrpStackLocation(Irp);
2487 
2488     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
2489     IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb;
2490     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
2491 
2492     IoSetCompletionRoutine(Irp,
2493                            USBH_ChangeIndication,
2494                            HubExtension,
2495                            TRUE,
2496                            TRUE,
2497                            TRUE);
2498 
2499     KeClearEvent(&HubExtension->StatusChangeEvent);
2500 
2501     Status = IoCallDriver(HubExtension->LowerDevice, Irp);
2502 
2503     return Status;
2504 }
2505 
2506 NTSTATUS
2507 NTAPI
USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_DEVICE_HANDLE * OutDeviceHandle,IN USB_PORT_STATUS UsbPortStatus,IN USHORT Port)2508 USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2509                     IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
2510                     IN USB_PORT_STATUS UsbPortStatus,
2511                     IN USHORT Port)
2512 {
2513     PUSB_DEVICE_HANDLE HubDeviceHandle;
2514     PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice;
2515 
2516     DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n",
2517            Port,
2518            UsbPortStatus.AsUshort16);
2519 
2520     CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice;
2521 
2522     if (!CreateUsbDevice)
2523     {
2524         return STATUS_NOT_IMPLEMENTED;
2525     }
2526 
2527     HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
2528 
2529     return CreateUsbDevice(HubExtension->BusInterface.BusContext,
2530                            OutDeviceHandle,
2531                            HubDeviceHandle,
2532                            UsbPortStatus.AsUshort16,
2533                            Port);
2534 }
2535 
2536 NTSTATUS
2537 NTAPI
USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_DEVICE_HANDLE DeviceHandle,IN ULONG Flags)2538 USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2539                     IN PUSB_DEVICE_HANDLE DeviceHandle,
2540                     IN ULONG Flags)
2541 {
2542     PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice;
2543 
2544     DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %X\n",
2545            DeviceHandle,
2546            Flags);
2547 
2548     RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice;
2549 
2550     if (!RemoveUsbDevice)
2551     {
2552         return STATUS_NOT_IMPLEMENTED;
2553     }
2554 
2555     return RemoveUsbDevice(HubExtension->BusInterface.BusContext,
2556                            DeviceHandle,
2557                            Flags);
2558 }
2559 
2560 NTSTATUS
2561 NTAPI
USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_DEVICE_HANDLE DeviceHandle,IN PUCHAR DeviceDescriptorBuffer,IN ULONG DeviceDescriptorBufferLength,IN PUCHAR ConfigDescriptorBuffer,IN ULONG ConfigDescriptorBufferLength)2562 USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2563                         IN PUSB_DEVICE_HANDLE DeviceHandle,
2564                         IN PUCHAR DeviceDescriptorBuffer,
2565                         IN ULONG DeviceDescriptorBufferLength,
2566                         IN PUCHAR ConfigDescriptorBuffer,
2567                         IN ULONG ConfigDescriptorBufferLength)
2568 {
2569     NTSTATUS Status;
2570     PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice;
2571     PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors;
2572 
2573     DPRINT("USBD_InitializeDeviceEx: ... \n");
2574 
2575     InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice;
2576     GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors;
2577 
2578     if (!InitializeUsbDevice || !GetUsbDescriptors)
2579     {
2580         return STATUS_NOT_IMPLEMENTED;
2581     }
2582 
2583     Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext,
2584                                  DeviceHandle);
2585 
2586     if (!NT_SUCCESS(Status))
2587     {
2588         return Status;
2589     }
2590 
2591     return GetUsbDescriptors(HubExtension->BusInterface.BusContext,
2592                              DeviceHandle,
2593                              DeviceDescriptorBuffer,
2594                              &DeviceDescriptorBufferLength,
2595                              ConfigDescriptorBuffer,
2596                              &ConfigDescriptorBufferLength);
2597 }
2598 
2599 VOID
2600 NTAPI
USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PDEVICE_OBJECT UsbDevicePdo,IN PVOID DeviceHandle)2601 USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,
2602                            IN PDEVICE_OBJECT UsbDevicePdo,
2603                            IN PVOID DeviceHandle)
2604 {
2605     PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData;
2606 
2607     DPRINT("USBHUB_SetDeviceHandleData ... \n");
2608 
2609     SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData;
2610 
2611     if (!SetDeviceHandleData)
2612     {
2613         return;
2614     }
2615 
2616     SetDeviceHandleData(HubExtension->BusInterface.BusContext,
2617                         DeviceHandle,
2618                         UsbDevicePdo);
2619 }
2620 
2621 VOID
2622 NTAPI
USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)2623 USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)
2624 {
2625     PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers;
2626 
2627     DPRINT("USBHUB_FlushAllTransfers ... \n");
2628 
2629     FlushTransfers = HubExtension->BusInterface.FlushTransfers;
2630 
2631     if (FlushTransfers)
2632     {
2633         FlushTransfers(HubExtension->BusInterface.BusContext, NULL);
2634     }
2635 }
2636 
2637 NTSTATUS
2638 NTAPI
USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,IN ULONG Length,IN PUSB_DEVICE_HANDLE DeviceHandle)2639 USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
2640                             IN PUSBHUB_FDO_EXTENSION HubExtension,
2641                             IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
2642                             IN ULONG Length,
2643                             IN PUSB_DEVICE_HANDLE DeviceHandle)
2644 {
2645     PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
2646     PUSB_DEVICE_INFORMATION_0 DeviceInfo;
2647     SIZE_T DeviceInfoLength;
2648     PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo;
2649     SIZE_T NodeInfoLength;
2650     ULONG PipeNumber;
2651     ULONG dummy;
2652     NTSTATUS Status;
2653 
2654     DPRINT("USBD_GetDeviceInformationEx ... \n");
2655 
2656     QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
2657 
2658     if (!QueryDeviceInformation)
2659     {
2660         Status = STATUS_NOT_IMPLEMENTED;
2661         return Status;
2662     }
2663 
2664     DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0);
2665 
2666     while (TRUE)
2667     {
2668         DeviceInfo = ExAllocatePoolWithTag(PagedPool,
2669                                            DeviceInfoLength,
2670                                            USB_HUB_TAG);
2671 
2672         if (!DeviceInfo)
2673         {
2674             return STATUS_INSUFFICIENT_RESOURCES;
2675         }
2676 
2677         RtlZeroMemory(DeviceInfo, DeviceInfoLength);
2678 
2679         DeviceInfo->InformationLevel = 0;
2680 
2681         Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
2682                                         DeviceHandle,
2683                                         DeviceInfo,
2684                                         DeviceInfoLength,
2685                                         &dummy);
2686 
2687         if (Status != STATUS_BUFFER_TOO_SMALL)
2688         {
2689             break;
2690         }
2691 
2692         DeviceInfoLength = DeviceInfo->ActualLength;
2693 
2694         ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2695     }
2696 
2697     NodeInfo = NULL;
2698     NodeInfoLength = 0;
2699 
2700     if (NT_SUCCESS(Status))
2701     {
2702         NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) +
2703                          DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO);
2704 
2705         NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG);
2706 
2707         if (!NodeInfo)
2708         {
2709             ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2710             return STATUS_INSUFFICIENT_RESOURCES;
2711         }
2712 
2713         RtlZeroMemory(NodeInfo, NodeInfoLength);
2714 
2715         NodeInfo->ConnectionIndex = Info->ConnectionIndex;
2716 
2717         RtlCopyMemory(&NodeInfo->DeviceDescriptor,
2718                       &DeviceInfo->DeviceDescriptor,
2719                       sizeof(USB_DEVICE_DESCRIPTOR));
2720 
2721         NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue;
2722         NodeInfo->Speed = DeviceInfo->DeviceSpeed;
2723         NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE;
2724         NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress;
2725         NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes;
2726         NodeInfo->ConnectionStatus = Info->ConnectionStatus;
2727 
2728         for (PipeNumber = 0;
2729              PipeNumber < DeviceInfo->NumberOfOpenPipes;
2730              PipeNumber++)
2731         {
2732             RtlCopyMemory(&NodeInfo->PipeList[PipeNumber],
2733                           &DeviceInfo->PipeList[PipeNumber],
2734                           sizeof(USB_PIPE_INFO));
2735         }
2736     }
2737 
2738     ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
2739 
2740     if (NodeInfo)
2741     {
2742         if (NodeInfoLength <= Length)
2743         {
2744             Length = NodeInfoLength;
2745         }
2746         else
2747         {
2748             Status = STATUS_BUFFER_TOO_SMALL;
2749         }
2750 
2751         RtlCopyMemory(Info, NodeInfo, Length);
2752 
2753         ExFreePoolWithTag(NodeInfo, USB_HUB_TAG);
2754     }
2755 
2756     return Status;
2757 }
2758 
2759 NTSTATUS
2760 NTAPI
USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)2761 USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
2762                      IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
2763                      IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)
2764 {
2765     PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice;
2766     NTSTATUS Status;
2767 
2768     DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n",
2769            HubExtension,
2770            OldDeviceHandle,
2771            NewDeviceHandle);
2772 
2773     RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice;
2774 
2775     if (RestoreUsbDevice)
2776     {
2777         Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext,
2778                                   OldDeviceHandle,
2779                                   NewDeviceHandle);
2780     }
2781     else
2782     {
2783         Status = STATUS_NOT_IMPLEMENTED;
2784     }
2785 
2786     return Status;
2787 }
2788 
2789 NTSTATUS
2790 NTAPI
USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,PUSBHUB_WORKER_ROUTINE WorkerRoutine,SIZE_T BufferLength,PVOID * OutHubWorkItemBuffer,WORK_QUEUE_TYPE Type)2791 USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,
2792                       PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
2793                       PUSBHUB_WORKER_ROUTINE WorkerRoutine,
2794                       SIZE_T BufferLength,
2795                       PVOID * OutHubWorkItemBuffer,
2796                       WORK_QUEUE_TYPE Type)
2797 {
2798     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
2799     PIO_WORKITEM WorkItem;
2800     PVOID WorkItemBuffer;
2801 
2802     DPRINT("USBH_AllocateWorkItem: ... \n");
2803 
2804     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT))
2805     {
2806         return STATUS_INVALID_PARAMETER;
2807     }
2808 
2809     HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool,
2810                                           sizeof(USBHUB_IO_WORK_ITEM),
2811                                           USB_HUB_TAG);
2812 
2813     if (!HubIoWorkItem)
2814     {
2815         return STATUS_INSUFFICIENT_RESOURCES;
2816     }
2817 
2818     RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM));
2819 
2820     WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice);
2821 
2822     HubIoWorkItem->HubWorkItem = WorkItem;
2823 
2824     if (!WorkItem)
2825     {
2826         ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2827         return STATUS_INSUFFICIENT_RESOURCES;
2828     }
2829 
2830     if (BufferLength && OutHubWorkItemBuffer)
2831     {
2832         WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2833                                                BufferLength,
2834                                                USB_HUB_TAG);
2835 
2836         HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer;
2837 
2838         if (!WorkItemBuffer)
2839         {
2840             IoFreeWorkItem(HubIoWorkItem->HubWorkItem);
2841             ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2842 
2843             return STATUS_INSUFFICIENT_RESOURCES;
2844         }
2845 
2846         RtlZeroMemory(WorkItemBuffer, BufferLength);
2847     }
2848     else
2849     {
2850         HubIoWorkItem->HubWorkItemBuffer = NULL;
2851     }
2852 
2853     HubIoWorkItem->HubWorkItemType = Type;
2854     HubIoWorkItem->HubExtension = HubExtension;
2855     HubIoWorkItem->HubWorkerRoutine = WorkerRoutine;
2856 
2857     if (OutHubIoWorkItem)
2858     {
2859         *OutHubIoWorkItem = HubIoWorkItem;
2860     }
2861 
2862     if (OutHubWorkItemBuffer)
2863     {
2864         *OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer;
2865     }
2866 
2867     return STATUS_SUCCESS;
2868 }
2869 
2870 VOID
2871 NTAPI
USBH_Worker(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context)2872 USBH_Worker(IN PDEVICE_OBJECT DeviceObject,
2873             IN PVOID Context)
2874 {
2875     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
2876     PUSBHUB_FDO_EXTENSION HubExtension;
2877     KIRQL OldIrql;
2878     PIO_WORKITEM WorkItem;
2879 
2880     DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context);
2881 
2882     HubIoWorkItem = Context;
2883 
2884     InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued);
2885 
2886     HubExtension = HubIoWorkItem->HubExtension;
2887     WorkItem = HubIoWorkItem->HubWorkItem;
2888 
2889     HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension,
2890                                     HubIoWorkItem->HubWorkItemBuffer);
2891 
2892     KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql);
2893     RemoveEntryList(&HubIoWorkItem->HubWorkItemLink);
2894     KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql);
2895 
2896     if (HubIoWorkItem->HubWorkItemBuffer)
2897     {
2898         ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
2899     }
2900 
2901     ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2902 
2903     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
2904     {
2905         KeSetEvent(&HubExtension->PendingRequestEvent,
2906                    EVENT_INCREMENT,
2907                    FALSE);
2908     }
2909 
2910     IoFreeWorkItem(WorkItem);
2911 
2912     DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context);
2913 }
2914 
2915 VOID
2916 NTAPI
USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)2917 USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,
2918                    IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
2919 {
2920     DPRINT("USBH_QueueWorkItem: ... \n");
2921 
2922     InterlockedIncrement(&HubExtension->PendingRequestCount);
2923     InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued);
2924 
2925     ExInterlockedInsertTailList(&HubExtension->WorkItemList,
2926                                 &HubIoWorkItem->HubWorkItemLink,
2927                                 &HubExtension->WorkItemSpinLock);
2928 
2929     IoQueueWorkItem(HubIoWorkItem->HubWorkItem,
2930                     USBH_Worker,
2931                     HubIoWorkItem->HubWorkItemType,
2932                     HubIoWorkItem);
2933 }
2934 
2935 VOID
2936 NTAPI
USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)2937 USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
2938 {
2939     PIO_WORKITEM WorkItem;
2940 
2941     DPRINT("USBH_FreeWorkItem: ... \n");
2942 
2943     WorkItem = HubIoWorkItem->HubWorkItem;
2944 
2945     if (HubIoWorkItem->HubWorkItemBuffer)
2946     {
2947         ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
2948     }
2949 
2950     ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
2951 
2952     IoFreeWorkItem(WorkItem);
2953 }
2954 
2955 VOID
2956 NTAPI
USBHUB_RootHubCallBack(IN PVOID Context)2957 USBHUB_RootHubCallBack(IN PVOID Context)
2958 {
2959     PUSBHUB_FDO_EXTENSION HubExtension;
2960 
2961     DPRINT("USBHUB_RootHubCallBack: ... \n");
2962 
2963     HubExtension = Context;
2964 
2965     if (HubExtension->SCEIrp)
2966     {
2967         HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION |
2968                                    USBHUB_FDO_FLAG_NOT_ENUMERATED);
2969 
2970         USBH_SubmitStatusChangeTransfer(HubExtension);
2971 
2972         IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
2973     }
2974     else
2975     {
2976         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
2977     }
2978 
2979     KeSetEvent(&HubExtension->RootHubNotificationEvent,
2980                EVENT_INCREMENT,
2981                FALSE);
2982 }
2983 
2984 NTSTATUS
2985 NTAPI
USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)2986 USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
2987 {
2988     PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
2989 
2990     DPRINT("USBD_RegisterRootHubCallBack: ... \n");
2991 
2992     RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
2993 
2994     if (!RootHubInitNotification)
2995     {
2996         return STATUS_NOT_IMPLEMENTED;
2997     }
2998 
2999     KeClearEvent(&HubExtension->RootHubNotificationEvent);
3000 
3001     return RootHubInitNotification(HubExtension->BusInterface.BusContext,
3002                                    HubExtension,
3003                                    USBHUB_RootHubCallBack);
3004 }
3005 
3006 NTSTATUS
3007 NTAPI
USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)3008 USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
3009 {
3010     PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
3011     NTSTATUS Status;
3012 
3013     DPRINT("USBD_UnRegisterRootHubCallBack ... \n");
3014 
3015     RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
3016 
3017     if (!RootHubInitNotification)
3018     {
3019         return STATUS_NOT_IMPLEMENTED;
3020     }
3021 
3022     Status = RootHubInitNotification(HubExtension->BusInterface.BusContext,
3023                                      NULL,
3024                                      NULL);
3025 
3026     if (!NT_SUCCESS(Status))
3027     {
3028         KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent,
3029                               Executive,
3030                               KernelMode,
3031                               FALSE,
3032                               NULL);
3033     }
3034 
3035     return Status;
3036 }
3037 
3038 VOID
3039 NTAPI
USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)3040 USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,
3041                            IN UCHAR MinorFunction,
3042                            IN POWER_STATE PowerState,
3043                            IN PVOID Context,
3044                            IN PIO_STATUS_BLOCK IoStatus)
3045 {
3046     DPRINT("USBH_HubSetDWakeCompletion: ... \n");
3047     KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
3048 }
3049 
3050 VOID
3051 NTAPI
USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PLIST_ENTRY IdleList)3052 USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
3053                           IN PLIST_ENTRY IdleList)
3054 {
3055     PDEVICE_OBJECT PortDevice;
3056     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3057     PIRP IdleIrp;
3058     PIRP HubIdleIrp;
3059     ULONG NumPorts;
3060     ULONG Port;
3061     KIRQL Irql;
3062 
3063     DPRINT("USBH_HubQueuePortIdleIrps ... \n");
3064 
3065     InitializeListHead(IdleList);
3066 
3067     IoAcquireCancelSpinLock(&Irql);
3068 
3069     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
3070 
3071     for (Port = 0; Port < NumPorts; ++Port)
3072     {
3073         PortDevice = HubExtension->PortData[Port].DeviceObject;
3074 
3075         if (PortDevice)
3076         {
3077             PortExtension = PortDevice->DeviceExtension;
3078 
3079             IdleIrp = PortExtension->IdleNotificationIrp;
3080             PortExtension->IdleNotificationIrp = NULL;
3081 
3082             if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL))
3083             {
3084                 DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME\n");
3085                 DbgBreakPoint();
3086             }
3087         }
3088     }
3089 
3090     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
3091     {
3092         HubIdleIrp = HubExtension->PendingIdleIrp;
3093         HubExtension->PendingIdleIrp = NULL;
3094     }
3095     else
3096     {
3097         HubIdleIrp = NULL;
3098     }
3099 
3100     IoReleaseCancelSpinLock(Irql);
3101 
3102     if (HubIdleIrp)
3103     {
3104         USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp);
3105     }
3106 }
3107 
3108 VOID
3109 NTAPI
USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PLIST_ENTRY IdleList,IN NTSTATUS NtStatus)3110 USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
3111                                    IN PLIST_ENTRY IdleList,
3112                                    IN NTSTATUS NtStatus)
3113 {
3114     DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n");
3115 
3116     while (!IsListEmpty(IdleList))
3117     {
3118         DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME\n");
3119         DbgBreakPoint();
3120     }
3121 }
3122 
3123 VOID
3124 NTAPI
USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)3125 USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)
3126 {
3127     PDEVICE_OBJECT PortDevice;
3128     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3129     PLIST_ENTRY Entry;
3130     ULONG Port;
3131 
3132     DPRINT("USBH_FlushPortPwrList ... \n");
3133 
3134     InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount);
3135 
3136     KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3137                           Executive,
3138                           KernelMode,
3139                           FALSE,
3140                           NULL);
3141 
3142     for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; ++Port)
3143     {
3144         PortDevice = HubExtension->PortData[Port].DeviceObject;
3145 
3146         if (!PortDevice)
3147         {
3148             continue;
3149         }
3150 
3151         PortExtension = PortDevice->DeviceExtension;
3152 
3153         InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0);
3154 
3155         while (TRUE)
3156         {
3157             Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList,
3158                                                 &PortExtension->PortPowerListSpinLock);
3159 
3160             if (!Entry)
3161             {
3162                 break;
3163             }
3164 
3165             DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME\n");
3166             DbgBreakPoint();
3167         }
3168     }
3169 
3170     KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3171                        LOW_REALTIME_PRIORITY,
3172                        1,
3173                        FALSE);
3174 
3175     if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount))
3176     {
3177         KeSetEvent(&HubExtension->PendingRequestEvent,
3178                    EVENT_INCREMENT,
3179                    FALSE);
3180     }
3181 }
3182 
3183 VOID
3184 NTAPI
USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN NTSTATUS NtStatus)3185 USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
3186                              IN NTSTATUS NtStatus)
3187 {
3188     LIST_ENTRY IdleList;
3189 
3190     DPRINT("USBH_HubCompletePortIdleIrps ... \n");
3191 
3192     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
3193     {
3194         USBH_HubQueuePortIdleIrps(HubExtension, &IdleList);
3195 
3196         USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
3197                                            &IdleList,
3198                                            NtStatus);
3199 
3200         USBH_FlushPortPwrList(HubExtension);
3201     }
3202 }
3203 
3204 VOID
3205 NTAPI
USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP IdleIrp)3206 USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
3207                       IN PIRP IdleIrp)
3208 {
3209     DPRINT("USBH_HubCancelIdleIrp ... \n");
3210 
3211     IoCancelIrp(IdleIrp);
3212 
3213     if (InterlockedExchange(&HubExtension->IdleRequestLock, 1))
3214     {
3215         IoFreeIrp(IdleIrp);
3216     }
3217 }
3218 
3219 BOOLEAN
3220 NTAPI
USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,IN BOOLEAN IsWait,IN BOOLEAN IsExtCheck)3221 USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,
3222                     IN BOOLEAN IsWait,
3223                     IN BOOLEAN IsExtCheck)
3224 {
3225     PDEVICE_OBJECT PdoDevice;
3226     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3227     PUSBHUB_PORT_DATA PortData;
3228     ULONG Port;
3229     BOOLEAN Result = FALSE;
3230 
3231     DPRINT("USBH_CheckIdleAbort: ... \n");
3232 
3233     InterlockedIncrement(&HubExtension->PendingRequestCount);
3234 
3235     if (IsWait == TRUE)
3236     {
3237         KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3238                               Executive,
3239                               KernelMode,
3240                               FALSE,
3241                               NULL);
3242     }
3243 
3244     PortData = HubExtension->PortData;
3245 
3246     for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
3247     {
3248         PdoDevice = PortData[Port].DeviceObject;
3249 
3250         if (PdoDevice)
3251         {
3252             PortExtension = PdoDevice->DeviceExtension;
3253 
3254             if (PortExtension->PoRequestCounter)
3255             {
3256                 Result = TRUE;
3257                 goto Wait;
3258             }
3259         }
3260     }
3261 
3262     if (IsExtCheck == TRUE)
3263     {
3264         PortData = HubExtension->PortData;
3265 
3266         for (Port = 0;
3267              Port < HubExtension->HubDescriptor->bNumberOfPorts;
3268              Port++)
3269         {
3270             PdoDevice = PortData[Port].DeviceObject;
3271 
3272             if (PdoDevice)
3273             {
3274                 PortExtension = PdoDevice->DeviceExtension;
3275                 InterlockedExchange(&PortExtension->StateBehindD2, 0);
3276             }
3277         }
3278     }
3279 
3280 Wait:
3281 
3282     if (IsWait == TRUE)
3283     {
3284         KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3285                            LOW_REALTIME_PRIORITY,
3286                            1,
3287                            FALSE);
3288     }
3289 
3290     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3291     {
3292         KeSetEvent(&HubExtension->PendingRequestEvent,
3293                    EVENT_INCREMENT,
3294                    FALSE);
3295     }
3296 
3297     return Result;
3298 }
3299 
3300 VOID
3301 NTAPI
USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)3302 USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
3303                               IN UCHAR MinorFunction,
3304                               IN POWER_STATE PowerState,
3305                               IN PVOID Context,
3306                               IN PIO_STATUS_BLOCK IoStatus)
3307 {
3308     DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n");
3309 }
3310 
3311 NTSTATUS
3312 NTAPI
USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)3313 USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
3314 {
3315     POWER_STATE PowerState;
3316     NTSTATUS Status;
3317     PIRP Irp = NULL;
3318     KIRQL Irql;
3319 
3320     DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n");
3321 
3322     PowerState.SystemState = HubExtension->SystemWake;
3323     HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
3324 
3325     InterlockedIncrement(&HubExtension->PendingRequestCount);
3326     InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0);
3327 
3328     Status = PoRequestPowerIrp(HubExtension->LowerPDO,
3329                                IRP_MN_WAIT_WAKE,
3330                                PowerState,
3331                                USBH_FdoWaitWakeIrpCompletion,
3332                                HubExtension,
3333                                &Irp);
3334 
3335     IoAcquireCancelSpinLock(&Irql);
3336 
3337     if (Status == STATUS_PENDING)
3338     {
3339         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)
3340         {
3341             HubExtension->PendingWakeIrp = Irp;
3342             DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n",
3343                    HubExtension->PendingWakeIrp);
3344         }
3345     }
3346     else
3347     {
3348         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
3349 
3350         if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3351         {
3352             KeSetEvent(&HubExtension->PendingRequestEvent,
3353                        EVENT_INCREMENT,
3354                        FALSE);
3355         }
3356     }
3357 
3358     IoReleaseCancelSpinLock(Irql);
3359 
3360     return Status;
3361 }
3362 
3363 VOID
3364 NTAPI
USBH_FdoIdleNotificationCallback(IN PVOID Context)3365 USBH_FdoIdleNotificationCallback(IN PVOID Context)
3366 {
3367     PUSBHUB_FDO_EXTENSION HubExtension;
3368     PUSBHUB_PORT_DATA PortData;
3369     PDEVICE_OBJECT PortDevice;
3370     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3371     PIRP Irp = NULL;
3372     PIRP IdleIrp;
3373     POWER_STATE PowerState;
3374     KEVENT Event;
3375     ULONG Port;
3376     PIO_STACK_LOCATION IoStack;
3377     PUSB_IDLE_CALLBACK_INFO CallbackInfo;
3378     BOOLEAN IsReady;
3379     KIRQL OldIrql;
3380     NTSTATUS Status;
3381 
3382     HubExtension = Context;
3383 
3384     DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %lX\n",
3385            HubExtension,
3386            HubExtension->HubFlags);
3387 
3388     if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER |
3389                                   USBHUB_FDO_FLAG_WAKEUP_START |
3390                                   USBHUB_FDO_FLAG_DEVICE_REMOVED |
3391                                   USBHUB_FDO_FLAG_STATE_CHANGING |
3392                                   USBHUB_FDO_FLAG_ESD_RECOVERING |
3393                                   USBHUB_FDO_FLAG_DEVICE_FAILED |
3394                                   USBHUB_FDO_FLAG_DEVICE_STOPPING))
3395     {
3396         DbgBreakPoint();
3397         return;
3398     }
3399 
3400     HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE;
3401 
3402     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP))
3403     {
3404         Status = USBH_FdoSubmitWaitWakeIrp(HubExtension);
3405 
3406         if (Status != STATUS_PENDING)
3407         {
3408             DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n");
3409             DbgBreakPoint();
3410             HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
3411             return;
3412         }
3413     }
3414 
3415     InterlockedIncrement(&HubExtension->PendingRequestCount);
3416 
3417     KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3418                           Executive,
3419                           KernelMode,
3420                           FALSE,
3421                           NULL);
3422 
3423     PortData = HubExtension->PortData;
3424     IsReady = TRUE;
3425 
3426     for (Port = 0;
3427          Port < HubExtension->HubDescriptor->bNumberOfPorts;
3428          Port++)
3429     {
3430         PortDevice = PortData[Port].DeviceObject;
3431 
3432         if (PortDevice)
3433         {
3434             PortExtension = PortDevice->DeviceExtension;
3435 
3436             IdleIrp = PortExtension->IdleNotificationIrp;
3437 
3438             if (!IdleIrp)
3439             {
3440                 IsReady = FALSE;
3441                 goto IdleHub;
3442             }
3443 
3444             IoStack = IoGetCurrentIrpStackLocation(IdleIrp);
3445 
3446             CallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
3447 
3448             if (!CallbackInfo)
3449             {
3450                 IsReady = FALSE;
3451                 goto IdleHub;
3452             }
3453 
3454             if (!CallbackInfo->IdleCallback)
3455             {
3456                 IsReady = FALSE;
3457                 goto IdleHub;
3458             }
3459 
3460             if (PortExtension->PendingSystemPoRequest)
3461             {
3462                 IsReady = FALSE;
3463                 goto IdleHub;
3464             }
3465 
3466             if (InterlockedCompareExchange(&PortExtension->StateBehindD2,
3467                                            1,
3468                                            0))
3469             {
3470                 IsReady = FALSE;
3471                 goto IdleHub;
3472             }
3473 
3474             DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n",
3475                    CallbackInfo->IdleContext);
3476 
3477             CallbackInfo->IdleCallback(CallbackInfo->IdleContext);
3478 
3479             if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
3480             {
3481                 IsReady = FALSE;
3482                 goto IdleHub;
3483             }
3484         }
3485     }
3486 
3487     if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) &&
3488         (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) == TRUE))
3489     {
3490         IsReady = FALSE;
3491     }
3492 
3493 IdleHub:
3494 
3495     KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3496                        LOW_REALTIME_PRIORITY,
3497                        1,
3498                        FALSE);
3499 
3500     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3501     {
3502         KeSetEvent(&HubExtension->PendingRequestEvent,
3503                    EVENT_INCREMENT,
3504                    FALSE);
3505     }
3506 
3507     if (!IsReady ||
3508         (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED))
3509     {
3510         DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %lX\n",
3511                 HubExtension->HubFlags);
3512 
3513         HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
3514                                     USBHUB_FDO_FLAG_GOING_IDLE);
3515 
3516         /* Aborting Idle for Hub */
3517         IoAcquireCancelSpinLock(&OldIrql);
3518 
3519         if (HubExtension->PendingIdleIrp)
3520         {
3521             Irp = HubExtension->PendingIdleIrp;
3522             HubExtension->PendingIdleIrp = NULL;
3523         }
3524 
3525         IoReleaseCancelSpinLock(OldIrql);
3526 
3527         if (Irp)
3528         {
3529             USBH_HubCancelIdleIrp(HubExtension, Irp);
3530         }
3531 
3532         DbgBreakPoint();
3533         USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED);
3534     }
3535     else
3536     {
3537         PowerState.DeviceState = HubExtension->DeviceWake;
3538 
3539         KeWaitForSingleObject(&HubExtension->IdleSemaphore,
3540                               Executive,
3541                               KernelMode,
3542                               FALSE,
3543                               NULL);
3544 
3545         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
3546         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE;
3547 
3548         KeInitializeEvent(&Event, NotificationEvent, FALSE);
3549 
3550         DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n",
3551                 HubExtension->LowerPDO);
3552 
3553         DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n",
3554                PowerState.DeviceState);
3555 
3556         Status = PoRequestPowerIrp(HubExtension->LowerPDO,
3557                                    IRP_MN_SET_POWER,
3558                                    PowerState,
3559                                    USBH_HubSetDWakeCompletion,
3560                                    &Event,
3561                                    NULL);
3562 
3563         if (Status == STATUS_PENDING)
3564         {
3565             KeWaitForSingleObject(&Event,
3566                                   Executive,
3567                                   KernelMode,
3568                                   FALSE,
3569                                   NULL);
3570         }
3571     }
3572 }
3573 
3574 VOID
3575 NTAPI
USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)3576 USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3577                                 IN PVOID Context)
3578 {
3579     PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext;
3580     NTSTATUS NtStatus;
3581     NTSTATUS Status;
3582     BOOLEAN IsFlush = FALSE;
3583 
3584     DPRINT("USBH_CompletePortIdleIrpsWorker ... \n");
3585 
3586     IdlePortContext = Context;
3587     NtStatus = IdlePortContext->Status;
3588 
3589     USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
3590                                        &IdlePortContext->PwrList,
3591                                        NtStatus);
3592 
3593     DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME\n");
3594     Status = STATUS_NOT_IMPLEMENTED;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush);
3595 
3596     if (NT_SUCCESS(Status))
3597     {
3598         if (IsFlush)
3599         {
3600             USBH_FlushPortPwrList(HubExtension);
3601         }
3602     }
3603 }
3604 
3605 VOID
3606 NTAPI
USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)3607 USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3608                                 IN PVOID Context)
3609 {
3610     PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
3611 
3612     DPRINT("USBH_IdleCompletePowerHubWorker ... \n");
3613 
3614     if (HubExtension &&
3615         HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
3616         HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
3617     {
3618         USBH_HubSetD0(HubExtension);
3619     }
3620 
3621     HubWorkItemBuffer = Context;
3622 
3623     USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status);
3624 
3625 }
3626 
3627 NTSTATUS
3628 NTAPI
USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)3629 USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,
3630                                         IN PIRP Irp,
3631                                         IN PVOID Context)
3632 {
3633     PUSBHUB_FDO_EXTENSION HubExtension;
3634     NTSTATUS NtStatus;
3635     PVOID IdleIrp;
3636     KIRQL Irql;
3637     NTSTATUS Status;
3638     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
3639 
3640     IoAcquireCancelSpinLock(&Irql);
3641 
3642     HubExtension = Context;
3643     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3644 
3645     IdleIrp = InterlockedExchangePointer((PVOID)&HubExtension->PendingIdleIrp,
3646                                          NULL);
3647 
3648     DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp);
3649 
3650     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3651     {
3652         KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
3653     }
3654 
3655     IoReleaseCancelSpinLock(Irql);
3656 
3657     NtStatus = Irp->IoStatus.Status;
3658 
3659     DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %lX\n",
3660            NtStatus);
3661 
3662     if (!NT_SUCCESS(NtStatus) &&
3663         NtStatus != STATUS_POWER_STATE_INVALID &&
3664         !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) &&
3665         !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
3666     {
3667         DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n",
3668                HubExtension->CurrentPowerState.DeviceState);
3669 
3670         if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
3671         {
3672             PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer;
3673 
3674             Status = USBH_AllocateWorkItem(HubExtension,
3675                                            &HubIoWorkItem,
3676                                            USBH_CompletePortIdleIrpsWorker,
3677                                            sizeof(USBHUB_IDLE_PORT_CONTEXT),
3678                                            (PVOID *)&HubWorkItemBuffer,
3679                                            DelayedWorkQueue);
3680 
3681             if (NT_SUCCESS(Status))
3682             {
3683                 HubWorkItemBuffer->Status = NtStatus;
3684 
3685                 USBH_HubQueuePortIdleIrps(HubExtension,
3686                                           &HubWorkItemBuffer->PwrList);
3687 
3688                 USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3689             }
3690         }
3691         else
3692         {
3693             PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
3694 
3695             Status = USBH_AllocateWorkItem(HubExtension,
3696                                            &HubIoWorkItem,
3697                                            USBH_IdleCompletePowerHubWorker,
3698                                            sizeof(USBHUB_IDLE_HUB_CONTEXT),
3699                                            (PVOID *)&HubWorkItemBuffer,
3700                                            DelayedWorkQueue);
3701 
3702             if (NT_SUCCESS(Status))
3703             {
3704                 HubWorkItemBuffer->Status = NtStatus;
3705                 USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3706             }
3707         }
3708     }
3709 
3710     if (IdleIrp ||
3711         InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1))
3712     {
3713         DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp);
3714         IoFreeIrp(Irp);
3715     }
3716 
3717     return STATUS_MORE_PROCESSING_REQUIRED;
3718 }
3719 
3720 NTSTATUS
3721 NTAPI
USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)3722 USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
3723 {
3724     NTSTATUS Status;
3725     ULONG HubFlags;
3726     PDEVICE_OBJECT LowerPDO;
3727     PIRP Irp;
3728     PIO_STACK_LOCATION IoStack;
3729     KIRQL Irql;
3730 
3731     DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n",
3732            HubExtension,
3733            HubExtension->PendingIdleIrp);
3734 
3735     if (HubExtension->PendingIdleIrp)
3736     {
3737         Status = STATUS_DEVICE_BUSY;
3738         KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3739         return Status;
3740     }
3741 
3742     HubFlags = HubExtension->HubFlags;
3743 
3744     if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
3745         HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED)
3746     {
3747         HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3748         KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3749         return STATUS_DEVICE_REMOVED;
3750     }
3751 
3752     LowerPDO = HubExtension->LowerPDO;
3753 
3754     HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback;
3755     HubExtension->IdleCallbackInfo.IdleContext = HubExtension;
3756 
3757     Irp = IoAllocateIrp(LowerPDO->StackSize, FALSE);
3758 
3759     if (!Irp)
3760     {
3761         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3762         Status = STATUS_INSUFFICIENT_RESOURCES;
3763 
3764         KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3765         return Status;
3766     }
3767 
3768     IoStack = IoGetNextIrpStackLocation(Irp);
3769 
3770     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
3771 
3772     IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO);
3773     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
3774     IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo;
3775 
3776     IoSetCompletionRoutine(Irp,
3777                            USBH_FdoIdleNotificationRequestComplete,
3778                            HubExtension,
3779                            TRUE,
3780                            TRUE,
3781                            TRUE);
3782 
3783     InterlockedIncrement(&HubExtension->PendingRequestCount);
3784     InterlockedExchange(&HubExtension->IdleRequestLock, 0);
3785 
3786     HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
3787                                 USBHUB_FDO_FLAG_GOING_IDLE);
3788 
3789     Status = IoCallDriver(HubExtension->LowerPDO, Irp);
3790 
3791     IoAcquireCancelSpinLock(&Irql);
3792 
3793     if (Status == STATUS_PENDING &&
3794         HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
3795     {
3796         HubExtension->PendingIdleIrp = Irp;
3797     }
3798 
3799     IoReleaseCancelSpinLock(Irql);
3800 
3801     KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
3802 
3803     return Status;
3804 }
3805 
3806 VOID
3807 NTAPI
USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)3808 USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)
3809 {
3810     PDEVICE_OBJECT PdoDevice;
3811     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
3812     PUSBHUB_PORT_DATA PortData;
3813     ULONG HubFlags;
3814     ULONG Port;
3815     KIRQL Irql;
3816     BOOLEAN IsHubIdle = FALSE;
3817     BOOLEAN IsAllPortsIdle;
3818     BOOLEAN IsHubCheck = TRUE;
3819 
3820     DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension);
3821 
3822 return; //HACK: delete it line after fixing Power Manager!!!
3823 
3824     KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3825 
3826     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK)
3827     {
3828         KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3829         return;
3830     }
3831 
3832     HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3833     KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3834 
3835     if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking)
3836     {
3837         KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3838         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3839         KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3840         return;
3841     }
3842 
3843     HubFlags = HubExtension->HubFlags;
3844     DPRINT("USBH_CheckHubIdle: HubFlags - %lX\n", HubFlags);
3845 
3846     if (!(HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) ||
3847         !(HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
3848     {
3849         goto Exit;
3850     }
3851 
3852     if (HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED ||
3853         HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER ||
3854         HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
3855         HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
3856         HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED ||
3857         HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING ||
3858         HubFlags & USBHUB_FDO_FLAG_WAKEUP_START ||
3859         HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
3860     {
3861         goto Exit;
3862     }
3863 
3864     if (HubExtension->ResetRequestCount)
3865     {
3866         HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
3867         goto Exit;
3868     }
3869 
3870     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
3871 
3872     InterlockedIncrement(&HubExtension->PendingRequestCount);
3873 
3874     KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
3875                           Executive,
3876                           KernelMode,
3877                           FALSE,
3878                           NULL);
3879 
3880     IoAcquireCancelSpinLock(&Irql);
3881 
3882     IsAllPortsIdle = TRUE;
3883 
3884     PortData = HubExtension->PortData;
3885 
3886     for (Port = 0;
3887          Port < HubExtension->HubDescriptor->bNumberOfPorts;
3888          Port++)
3889     {
3890         PdoDevice = PortData[Port].DeviceObject;
3891 
3892         if (PdoDevice)
3893         {
3894             PortExtension = PdoDevice->DeviceExtension;
3895 
3896             if (!PortExtension->IdleNotificationIrp)
3897             {
3898                 DPRINT("USBH_CheckHubIdle: PortExtension - %p\n",
3899                        PortExtension);
3900 
3901                 IsAllPortsIdle = FALSE;
3902                 IsHubCheck = FALSE;
3903 
3904                 break;
3905             }
3906         }
3907     }
3908 
3909     if (IsHubCheck &&
3910         !(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST))
3911     {
3912         KeClearEvent(&HubExtension->IdleEvent);
3913         HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
3914         IsHubIdle = TRUE;
3915     }
3916 
3917     IoReleaseCancelSpinLock(Irql);
3918 
3919     KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
3920                        LOW_REALTIME_PRIORITY,
3921                        1,
3922                        FALSE);
3923 
3924     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
3925     {
3926         KeSetEvent(&HubExtension->PendingRequestEvent,
3927                    EVENT_INCREMENT,
3928                    FALSE);
3929     }
3930 
3931     DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n",
3932            IsAllPortsIdle,
3933            IsHubIdle);
3934 
3935     if (IsAllPortsIdle && IsHubIdle)
3936     {
3937         USBH_FdoSubmitIdleRequestIrp(HubExtension);
3938     }
3939 
3940 Exit:
3941     KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
3942     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
3943     KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
3944 }
3945 
3946 VOID
3947 NTAPI
USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)3948 USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
3949                      IN PVOID Context)
3950 {
3951     DPRINT("USBH_CheckIdleWorker: ... \n");
3952     USBH_CheckHubIdle(HubExtension);
3953 }
3954 
3955 VOID
3956 NTAPI
USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)3957 USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)
3958 {
3959     PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
3960     NTSTATUS Status;
3961 
3962     DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension);
3963 
3964     Status = USBH_AllocateWorkItem(HubExtension,
3965                                    &HubIoWorkItem,
3966                                    USBH_CheckIdleWorker,
3967                                    0,
3968                                    NULL,
3969                                    DelayedWorkQueue);
3970 
3971     DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem);
3972 
3973     if (NT_SUCCESS(Status))
3974     {
3975         USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
3976     }
3977 }
3978 
3979 VOID
3980 NTAPI
USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)3981 USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
3982 {
3983     PUSBHUB_FDO_EXTENSION HubExtension;
3984     ULONG State;
3985     SYSTEM_POWER_STATE SystemPowerState;
3986     PDEVICE_POWER_STATE pDeviceState;
3987 
3988     DPRINT("USBH_PdoSetCapabilities ... \n");
3989 
3990     HubExtension = PortExtension->HubExtension;
3991 
3992     PortExtension->Capabilities.Size = 64;
3993     PortExtension->Capabilities.Version = 1;
3994 
3995     PortExtension->Capabilities.Removable = 1;
3996     PortExtension->Capabilities.Address = PortExtension->PortNumber;
3997 
3998     if (PortExtension->SerialNumber)
3999     {
4000         PortExtension->Capabilities.UniqueID = 1;
4001     }
4002     else
4003     {
4004         PortExtension->Capabilities.UniqueID = 0;
4005     }
4006 
4007     PortExtension->Capabilities.RawDeviceOK = 0;
4008 
4009     RtlCopyMemory(PortExtension->Capabilities.DeviceState,
4010                   HubExtension->DeviceState,
4011                   (PowerSystemMaximum + 2) * sizeof(POWER_STATE));
4012 
4013     PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0;
4014 
4015     if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP)
4016     {
4017         PortExtension->Capabilities.DeviceWake = PowerDeviceD2;
4018 
4019         PortExtension->Capabilities.DeviceD1 = 1;
4020         PortExtension->Capabilities.DeviceD2 = 1;
4021 
4022         PortExtension->Capabilities.WakeFromD0 = 1;
4023         PortExtension->Capabilities.WakeFromD1 = 1;
4024         PortExtension->Capabilities.WakeFromD2 = 1;
4025 
4026         pDeviceState = &PortExtension->Capabilities.DeviceState[2];
4027 
4028         for (State = 2; State <= 5; State++)
4029         {
4030             SystemPowerState = State;
4031 
4032             if (PortExtension->Capabilities.SystemWake < SystemPowerState)
4033             {
4034                 *pDeviceState = PowerDeviceD3;
4035             }
4036             else
4037             {
4038                 *pDeviceState = PowerDeviceD2;
4039             }
4040 
4041             ++pDeviceState;
4042         }
4043     }
4044     else
4045     {
4046         PortExtension->Capabilities.DeviceWake = PowerDeviceD0;
4047         PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3;
4048         PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3;
4049         PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3;
4050         PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3;
4051     }
4052 }
4053 
4054 NTSTATUS
4055 NTAPI
USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)4056 USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
4057 {
4058     PUSB_INTERFACE_DESCRIPTOR Pid;
4059     PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
4060     NTSTATUS Status;
4061 
4062     DPRINT("USBH_ProcessDeviceInformation ... \n");
4063 
4064     ConfigDescriptor = NULL;
4065 
4066     RtlZeroMemory(&PortExtension->InterfaceDescriptor,
4067                   sizeof(PortExtension->InterfaceDescriptor));
4068 
4069     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE;
4070 
4071     Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice,
4072                                              &ConfigDescriptor);
4073 
4074     if (!NT_SUCCESS(Status))
4075     {
4076         if (ConfigDescriptor)
4077         {
4078             ExFreePool(ConfigDescriptor);
4079         }
4080 
4081         return Status;
4082     }
4083 
4084     PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP;
4085 
4086     if (ConfigDescriptor->bmAttributes & 0x20)
4087     {
4088         /* device configuration supports remote wakeup */
4089         PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP;
4090     }
4091 
4092     USBHUB_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor);
4093     USBHUB_DumpingConfiguration(ConfigDescriptor);
4094 
4095     DPRINT_PNP("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n",
4096                PortExtension->DeviceDescriptor.bDeviceClass,
4097                PortExtension->DeviceDescriptor.bDeviceSubClass,
4098                PortExtension->DeviceDescriptor.bDeviceProtocol);
4099 
4100     DPRINT_PNP("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n",
4101                PortExtension->DeviceDescriptor.bNumConfigurations,
4102                ConfigDescriptor->bNumInterfaces);
4103 
4104 
4105     /* Enumeration of USB Composite Devices (msdn):
4106        1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
4107        or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol)
4108        fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively,
4109        as explained in USB Interface Association Descriptor.
4110        2) The device must have multiple interfaces
4111        3) The device must have a single configuration.
4112     */
4113 
4114     if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) ||
4115         (PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_MISCELLANEOUS &&
4116          PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 &&
4117          PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) &&
4118          (ConfigDescriptor->bNumInterfaces > 1) &&
4119          (PortExtension->DeviceDescriptor.bNumConfigurations < 2))
4120     {
4121         DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n");
4122 
4123         PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE;
4124 
4125         if (ConfigDescriptor)
4126         {
4127             ExFreePool(ConfigDescriptor);
4128         }
4129 
4130         return Status;
4131     }
4132 
4133     Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor,
4134                                               ConfigDescriptor,
4135                                               -1,
4136                                               -1,
4137                                               -1,
4138                                               -1,
4139                                               -1);
4140     if (Pid)
4141     {
4142         RtlCopyMemory(&PortExtension->InterfaceDescriptor,
4143                       Pid,
4144                       sizeof(PortExtension->InterfaceDescriptor));
4145 
4146         if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB)
4147         {
4148             PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE |
4149                                             USBHUB_PDO_FLAG_REMOTE_WAKEUP);
4150         }
4151     }
4152     else
4153     {
4154         Status = STATUS_UNSUCCESSFUL;
4155     }
4156 
4157     if (ConfigDescriptor)
4158     {
4159         ExFreePool(ConfigDescriptor);
4160     }
4161 
4162     return Status;
4163 }
4164 
4165 BOOLEAN
4166 NTAPI
USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT idVendor,IN USHORT idProduct,IN PVOID SerialNumber,IN USHORT SN_DescriptorLength)4167 USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,
4168                          IN USHORT idVendor,
4169                          IN USHORT idProduct,
4170                          IN PVOID SerialNumber,
4171                          IN USHORT SN_DescriptorLength)
4172 {
4173     PDEVICE_OBJECT PortDevice;
4174     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
4175     ULONG Port;
4176     SIZE_T NumberBytes;
4177 
4178     DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n",
4179            idVendor,
4180            idProduct);
4181 
4182     if (!HubExtension->HubDescriptor->bNumberOfPorts)
4183     {
4184         return TRUE;
4185     }
4186 
4187     for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
4188     {
4189         PortDevice = HubExtension->PortData[Port].DeviceObject;
4190 
4191         if (PortDevice)
4192         {
4193             PortExtension = PortDevice->DeviceExtension;
4194 
4195             if (PortExtension->DeviceDescriptor.idVendor == idVendor &&
4196                 PortExtension->DeviceDescriptor.idProduct == idProduct &&
4197                 PortExtension->SN_DescriptorLength == SN_DescriptorLength)
4198             {
4199                 if (PortExtension->SerialNumber)
4200                 {
4201                     NumberBytes = RtlCompareMemory(PortExtension->SerialNumber,
4202                                                    SerialNumber,
4203                                                    SN_DescriptorLength);
4204 
4205                     if (NumberBytes == SN_DescriptorLength)
4206                     {
4207                         return FALSE;
4208                     }
4209                 }
4210             }
4211         }
4212     }
4213 
4214     return TRUE;
4215 }
4216 
4217 BOOLEAN
4218 NTAPI
USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString)4219 USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString)
4220 {
4221     USHORT ix;
4222     USHORT Symbol;
4223 
4224     DPRINT("USBH_ValidateSerialNumberString: ... \n");
4225 
4226     for (ix = 0; SerialNumberString[ix] != UNICODE_NULL; ix++)
4227     {
4228         Symbol = SerialNumberString[ix];
4229 
4230         if (Symbol < 0x20 || Symbol > 0x7F || Symbol == 0x2C) // ','
4231         {
4232             return FALSE;
4233         }
4234     }
4235 
4236     return TRUE;
4237 }
4238 
4239 
4240 NTSTATUS
4241 NTAPI
USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject,IN USHORT LanguageId)4242 USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject,
4243                          IN USHORT LanguageId)
4244 {
4245     PUSB_STRING_DESCRIPTOR Descriptor;
4246     NTSTATUS Status;
4247     ULONG NumSymbols;
4248     ULONG ix;
4249     PWCHAR pSymbol;
4250     ULONG Length;
4251 
4252     DPRINT("USBH_CheckDeviceLanguage: LanguageId - 0x%04X\n", LanguageId);
4253 
4254     Descriptor = ExAllocatePoolWithTag(NonPagedPool,
4255                                        MAXIMUM_USB_STRING_LENGTH,
4256                                        USB_HUB_TAG);
4257 
4258     if (!Descriptor)
4259     {
4260         return STATUS_INSUFFICIENT_RESOURCES;
4261     }
4262 
4263     RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
4264 
4265     Status = USBH_SyncGetStringDescriptor(DeviceObject,
4266                                           0,
4267                                           0,
4268                                           Descriptor,
4269                                           MAXIMUM_USB_STRING_LENGTH,
4270                                           &Length,
4271                                           TRUE);
4272 
4273     if (!NT_SUCCESS(Status) ||
4274         Length < sizeof(USB_COMMON_DESCRIPTOR))
4275     {
4276         goto Exit;
4277     }
4278 
4279     NumSymbols = (Length -
4280                   FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / sizeof(WCHAR);
4281 
4282     pSymbol = Descriptor->bString;
4283 
4284     for (ix = 1; ix < NumSymbols; ix++)
4285     {
4286         if (*pSymbol == (WCHAR)LanguageId)
4287         {
4288             Status = STATUS_SUCCESS;
4289             goto Exit;
4290         }
4291 
4292         pSymbol++;
4293     }
4294 
4295     Status = STATUS_NOT_SUPPORTED;
4296 
4297 Exit:
4298     ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
4299     return Status;
4300 }
4301 
4302 NTSTATUS
4303 NTAPI
USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject,IN LPWSTR * OutSerialNumber,IN PUSHORT OutDescriptorLength,IN USHORT LanguageId,IN UCHAR Index)4304 USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject,
4305                            IN LPWSTR * OutSerialNumber,
4306                            IN PUSHORT OutDescriptorLength,
4307                            IN USHORT LanguageId,
4308                            IN UCHAR Index)
4309 {
4310     PUSB_STRING_DESCRIPTOR Descriptor;
4311     NTSTATUS Status;
4312     LPWSTR SerialNumberBuffer = NULL;
4313     UCHAR StringLength;
4314     UCHAR Length;
4315 
4316     DPRINT("USBH_GetSerialNumberString: ... \n");
4317 
4318     *OutSerialNumber = NULL;
4319     *OutDescriptorLength = 0;
4320 
4321     Descriptor = ExAllocatePoolWithTag(NonPagedPool,
4322                                        MAXIMUM_USB_STRING_LENGTH,
4323                                        USB_HUB_TAG);
4324 
4325     if (!Descriptor)
4326     {
4327         return STATUS_INSUFFICIENT_RESOURCES;
4328     }
4329 
4330     RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
4331 
4332     Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
4333 
4334     if (!NT_SUCCESS(Status))
4335     {
4336         goto Exit;
4337     }
4338 
4339     Status = USBH_SyncGetStringDescriptor(DeviceObject,
4340                                           Index,
4341                                           LanguageId,
4342                                           Descriptor,
4343                                           MAXIMUM_USB_STRING_LENGTH,
4344                                           NULL,
4345                                           TRUE);
4346 
4347     if (!NT_SUCCESS(Status) ||
4348         Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
4349     {
4350         Status = STATUS_INSUFFICIENT_RESOURCES;
4351         goto Exit;
4352     }
4353 
4354     StringLength = Descriptor->bLength -
4355                    FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
4356 
4357     Length = StringLength + sizeof(UNICODE_NULL);
4358 
4359     SerialNumberBuffer = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
4360 
4361     if (!SerialNumberBuffer)
4362     {
4363         goto Exit;
4364     }
4365 
4366     RtlZeroMemory(SerialNumberBuffer, Length);
4367     RtlCopyMemory(SerialNumberBuffer, Descriptor->bString, StringLength);
4368 
4369     *OutSerialNumber = SerialNumberBuffer;
4370     *OutDescriptorLength = Length;
4371 
4372 Exit:
4373     ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
4374     return Status;
4375 }
4376 
4377 NTSTATUS
4378 NTAPI
USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN USB_PORT_STATUS UsbPortStatus,IN ULONG IsWait)4379 USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
4380                   IN USHORT Port,
4381                   IN USB_PORT_STATUS UsbPortStatus,
4382                   IN ULONG IsWait)
4383 {
4384     ULONG PdoNumber = 0;
4385     WCHAR CharDeviceName[64];
4386     UNICODE_STRING DeviceName;
4387     PDEVICE_OBJECT DeviceObject = NULL;
4388     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
4389     PUSB_DEVICE_HANDLE DeviceHandle;
4390     LPWSTR SerialNumberBuffer;
4391     BOOLEAN IsHsDevice;
4392     BOOLEAN IsLsDevice;
4393     BOOLEAN IgnoringHwSerial = FALSE;
4394     NTSTATUS Status;
4395     UNICODE_STRING DestinationString;
4396 
4397     DPRINT("USBH_CreateDevice: Port - %x, UsbPortStatus - %lX\n",
4398            Port,
4399            UsbPortStatus.AsUshort16);
4400 
4401     do
4402     {
4403         RtlStringCbPrintfW(CharDeviceName,
4404                            sizeof(CharDeviceName),
4405                            L"\\Device\\USBPDO-%d",
4406                            PdoNumber);
4407 
4408         RtlInitUnicodeString(&DeviceName, CharDeviceName);
4409 
4410         Status = IoCreateDevice(HubExtension->Common.SelfDevice->DriverObject,
4411                                 sizeof(USBHUB_PORT_PDO_EXTENSION),
4412                                 &DeviceName,
4413                                 FILE_DEVICE_USB,
4414                                 0,
4415                                 FALSE,
4416                                 &DeviceObject);
4417 
4418         ++PdoNumber;
4419     }
4420     while (Status == STATUS_OBJECT_NAME_COLLISION);
4421 
4422     if (!NT_SUCCESS(Status))
4423     {
4424         ASSERT(Port > 0);
4425         HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
4426         return Status;
4427     }
4428 
4429     DeviceObject->StackSize = HubExtension->RootHubPdo2->StackSize;
4430 
4431     PortExtension = DeviceObject->DeviceExtension;
4432 
4433     DPRINT("USBH_CreateDevice: PortDevice - %p, <%wZ>\n", DeviceObject, &DeviceName);
4434     DPRINT("USBH_CreateDevice: PortExtension - %p\n", PortExtension);
4435 
4436     RtlZeroMemory(PortExtension, sizeof(USBHUB_PORT_PDO_EXTENSION));
4437 
4438     PortExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_PORT;
4439     PortExtension->Common.SelfDevice = DeviceObject;
4440 
4441     PortExtension->HubExtension = HubExtension;
4442     PortExtension->RootHubExtension = HubExtension;
4443 
4444     PortExtension->PortNumber = Port;
4445     PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
4446     PortExtension->IgnoringHwSerial = FALSE;
4447 
4448     KeInitializeSpinLock(&PortExtension->PortTimeoutSpinLock);
4449 
4450     InitializeListHead(&PortExtension->PortPowerList);
4451     KeInitializeSpinLock(&PortExtension->PortPowerListSpinLock);
4452 
4453     PortExtension->PoRequestCounter = 0;
4454     PortExtension->PendingSystemPoRequest = 0;
4455     PortExtension->PendingDevicePoRequest = 0;
4456     PortExtension->StateBehindD2 = 0;
4457 
4458     SerialNumberBuffer = NULL;
4459 
4460     IsHsDevice = UsbPortStatus.Usb20PortStatus.HighSpeedDeviceAttached;
4461     IsLsDevice = UsbPortStatus.Usb20PortStatus.LowSpeedDeviceAttached;
4462 
4463     if (IsLsDevice == 0)
4464     {
4465         if (IsHsDevice)
4466         {
4467             PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_HIGH_SPEED;
4468         }
4469     }
4470     else
4471     {
4472         PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_LOW_SPEED;
4473     }
4474 
4475     /* Initialize PortExtension->InstanceID */
4476     RtlInitUnicodeString(&DestinationString, (PCWSTR)&PortExtension->InstanceID);
4477     DestinationString.MaximumLength = 4 * sizeof(WCHAR);
4478     Status = RtlIntegerToUnicodeString(Port, 10, &DestinationString);
4479 
4480     DeviceObject->Flags |= DO_POWER_PAGABLE;
4481     DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4482 
4483     if (!NT_SUCCESS(Status))
4484     {
4485         DPRINT1("USBH_CreateDevice: IoCreateDevice() failed - %lX\n", Status);
4486         goto ErrorExit;
4487     }
4488 
4489     Status = USBD_CreateDeviceEx(HubExtension,
4490                                  &PortExtension->DeviceHandle,
4491                                  UsbPortStatus,
4492                                  Port);
4493 
4494     if (!NT_SUCCESS(Status))
4495     {
4496         DPRINT1("USBH_CreateDevice: USBD_CreateDeviceEx() failed - %lX\n", Status);
4497         goto ErrorExit;
4498     }
4499 
4500     Status = USBH_SyncResetPort(HubExtension, Port);
4501 
4502     if (!NT_SUCCESS(Status))
4503     {
4504         DPRINT1("USBH_CreateDevice: USBH_SyncResetPort() failed - %lX\n", Status);
4505         goto ErrorExit;
4506     }
4507 
4508     if (IsWait)
4509     {
4510         USBH_Wait(50);
4511     }
4512 
4513     Status = USBD_InitializeDeviceEx(HubExtension,
4514                                      PortExtension->DeviceHandle,
4515                                      (PUCHAR)&PortExtension->DeviceDescriptor,
4516                                      sizeof(USB_DEVICE_DESCRIPTOR),
4517                                      (PUCHAR)&PortExtension->ConfigDescriptor,
4518                                      sizeof(USB_CONFIGURATION_DESCRIPTOR));
4519 
4520     if (!NT_SUCCESS(Status))
4521     {
4522         DPRINT1("USBH_CreateDevice: USBD_InitializeDeviceEx() failed - %lX\n", Status);
4523         PortExtension->DeviceHandle = NULL;
4524         goto ErrorExit;
4525     }
4526 
4527     DPRINT1("USBH_RegQueryDeviceIgnoreHWSerNumFlag UNIMPLEMENTED. FIXME\n");
4528     //Status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(PortExtension->DeviceDescriptor.idVendor,
4529     //                                               PortExtension->DeviceDescriptor.idProduct,
4530     //                                               &IgnoringHwSerial);
4531 
4532     if (TRUE)//Status == STATUS_OBJECT_NAME_NOT_FOUND)
4533     {
4534         IgnoringHwSerial = FALSE;
4535     }
4536 
4537     if (IgnoringHwSerial)
4538     {
4539         PortExtension->IgnoringHwSerial = TRUE;
4540     }
4541 
4542     if (PortExtension->DeviceDescriptor.iSerialNumber &&
4543        !PortExtension->IgnoringHwSerial)
4544     {
4545         InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber, NULL);
4546 
4547         USBH_GetSerialNumberString(PortExtension->Common.SelfDevice,
4548                                    &SerialNumberBuffer,
4549                                    &PortExtension->SN_DescriptorLength,
4550                                    MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
4551                                    PortExtension->DeviceDescriptor.iSerialNumber);
4552 
4553         if (SerialNumberBuffer)
4554         {
4555             if (!USBH_ValidateSerialNumberString((PUSHORT)SerialNumberBuffer))
4556             {
4557                 ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
4558                 SerialNumberBuffer = NULL;
4559             }
4560 
4561             if (SerialNumberBuffer &&
4562                 !USBH_CheckDeviceIDUnique(HubExtension,
4563                                           PortExtension->DeviceDescriptor.idVendor,
4564                                           PortExtension->DeviceDescriptor.idProduct,
4565                                           SerialNumberBuffer,
4566                                           PortExtension->SN_DescriptorLength))
4567             {
4568                 ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
4569                 SerialNumberBuffer = NULL;
4570             }
4571         }
4572 
4573         InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
4574                                    SerialNumberBuffer);
4575     }
4576 
4577     Status = USBH_ProcessDeviceInformation(PortExtension);
4578 
4579     USBH_PdoSetCapabilities(PortExtension);
4580 
4581     if (NT_SUCCESS(Status))
4582     {
4583         goto Exit;
4584     }
4585 
4586 ErrorExit:
4587 
4588     PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INIT_PORT_FAILED;
4589 
4590     DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
4591                                               NULL);
4592 
4593     if (DeviceHandle)
4594     {
4595         USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
4596     }
4597 
4598     SerialNumberBuffer = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
4599                                                      NULL);
4600 
4601     if (SerialNumberBuffer)
4602     {
4603         ExFreePoolWithTag(SerialNumberBuffer, USB_HUB_TAG);
4604     }
4605 
4606 Exit:
4607 
4608     ASSERT(Port > 0);
4609     HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
4610     return Status;
4611 }
4612 
4613 NTSTATUS
4614 NTAPI
USBH_ResetDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,IN USHORT Port,IN BOOLEAN IsKeepDeviceData,IN BOOLEAN IsWait)4615 USBH_ResetDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
4616                  IN USHORT Port,
4617                  IN BOOLEAN IsKeepDeviceData,
4618                  IN BOOLEAN IsWait)
4619 {
4620     NTSTATUS Status;
4621     PUSBHUB_PORT_DATA PortData;
4622     PDEVICE_OBJECT PortDevice;
4623     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
4624     PVOID NewDeviceHandle;
4625     PVOID Handle;
4626     PVOID OldDeviceHandle;
4627     PUSB_DEVICE_HANDLE * DeviceHandle;
4628     USB_PORT_STATUS_AND_CHANGE PortStatus;
4629 
4630     DPRINT("USBH_ResetDevice: HubExtension - %p, Port - %x, IsKeepDeviceData - %x, IsWait - %x\n",
4631            HubExtension,
4632            Port,
4633            IsKeepDeviceData,
4634            IsWait);
4635 
4636     Status = USBH_SyncGetPortStatus(HubExtension,
4637                                     Port,
4638                                     &PortStatus,
4639                                     sizeof(USB_PORT_STATUS_AND_CHANGE));
4640 
4641     if (!NT_SUCCESS(Status) ||
4642         !(PortStatus.PortStatus.Usb20PortStatus.CurrentConnectStatus))
4643     {
4644         return STATUS_UNSUCCESSFUL;
4645     }
4646 
4647     InterlockedIncrement(&HubExtension->PendingRequestCount);
4648 
4649     KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
4650                           Executive,
4651                           KernelMode,
4652                           FALSE,
4653                           NULL);
4654 
4655     ASSERT(Port > 0);
4656     PortData = &HubExtension->PortData[Port-1];
4657 
4658     PortDevice = PortData->DeviceObject;
4659 
4660     if (!PortDevice)
4661     {
4662         Status = STATUS_INVALID_PARAMETER;
4663 
4664         KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
4665                            LOW_REALTIME_PRIORITY,
4666                            1,
4667                            FALSE);
4668 
4669         if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
4670         {
4671             KeSetEvent(&HubExtension->PendingRequestEvent,
4672                        EVENT_INCREMENT,
4673                        FALSE);
4674         }
4675 
4676         return Status;
4677     }
4678 
4679     PortExtension = PortDevice->DeviceExtension;
4680     DeviceHandle = &PortExtension->DeviceHandle;
4681 
4682     OldDeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
4683                                                  NULL);
4684 
4685     if (OldDeviceHandle)
4686     {
4687         if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOVING_PORT_PDO))
4688         {
4689             Status = USBD_RemoveDeviceEx(HubExtension,
4690                                          OldDeviceHandle,
4691                                          IsKeepDeviceData);
4692 
4693             PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
4694         }
4695     }
4696     else
4697     {
4698         OldDeviceHandle = NULL;
4699     }
4700 
4701     if (!NT_SUCCESS(Status))
4702     {
4703         goto ErrorExit;
4704     }
4705 
4706     Status = USBH_SyncResetPort(HubExtension, Port);
4707 
4708     if (!NT_SUCCESS(Status))
4709     {
4710         goto ErrorExit;
4711     }
4712 
4713     Status = USBH_SyncGetPortStatus(HubExtension,
4714                                     Port,
4715                                     &PortStatus,
4716                                     sizeof(USB_PORT_STATUS_AND_CHANGE));
4717 
4718     if (!NT_SUCCESS(Status))
4719     {
4720         goto ErrorExit;
4721     }
4722 
4723     Status = USBD_CreateDeviceEx(HubExtension,
4724                                  DeviceHandle,
4725                                  PortStatus.PortStatus,
4726                                  Port);
4727 
4728     if (!NT_SUCCESS(Status))
4729     {
4730         goto ErrorExit;
4731     }
4732 
4733     Status = USBH_SyncResetPort(HubExtension, Port);
4734 
4735     if (IsWait)
4736     {
4737         USBH_Wait(50);
4738     }
4739 
4740     if (!NT_SUCCESS(Status))
4741     {
4742         goto ErrorExit;
4743     }
4744 
4745     Status = USBD_InitializeDeviceEx(HubExtension,
4746                                      *DeviceHandle,
4747                                      &PortExtension->DeviceDescriptor.bLength,
4748                                      sizeof(PortExtension->DeviceDescriptor),
4749                                      &PortExtension->ConfigDescriptor.bLength,
4750                                      sizeof(PortExtension->ConfigDescriptor));
4751 
4752     if (NT_SUCCESS(Status))
4753     {
4754         if (IsKeepDeviceData)
4755         {
4756             Status = USBD_RestoreDeviceEx(HubExtension,
4757                                           OldDeviceHandle,
4758                                           *DeviceHandle);
4759 
4760             if (!NT_SUCCESS(Status))
4761             {
4762                 Handle = InterlockedExchangePointer(DeviceHandle, NULL);
4763 
4764                 USBD_RemoveDeviceEx(HubExtension, Handle, 0);
4765                 USBH_SyncDisablePort(HubExtension, Port);
4766 
4767                 Status = STATUS_NO_SUCH_DEVICE;
4768             }
4769         }
4770         else
4771         {
4772             PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOVING_PORT_PDO;
4773         }
4774 
4775         goto Exit;
4776     }
4777 
4778     *DeviceHandle = NULL;
4779 
4780 ErrorExit:
4781 
4782     NewDeviceHandle = InterlockedExchangePointer(DeviceHandle,
4783                                                  OldDeviceHandle);
4784 
4785     if (NewDeviceHandle)
4786     {
4787         Status = USBD_RemoveDeviceEx(HubExtension, NewDeviceHandle, 0);
4788     }
4789 
4790 Exit:
4791 
4792     KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
4793                        LOW_REALTIME_PRIORITY,
4794                        1,
4795                        FALSE);
4796 
4797     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
4798     {
4799         KeSetEvent(&HubExtension->PendingRequestEvent,
4800                    EVENT_INCREMENT,
4801                    FALSE);
4802     }
4803 
4804     return Status;
4805 }
4806 
4807 NTSTATUS
4808 NTAPI
USBH_PdoDispatch(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,IN PIRP Irp)4809 USBH_PdoDispatch(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
4810                  IN PIRP Irp)
4811 {
4812     PIO_STACK_LOCATION IoStack;
4813     UCHAR MajorFunction;
4814     BOOLEAN ShouldCompleteIrp;
4815     ULONG ControlCode;
4816     NTSTATUS Status;
4817 
4818     IoStack = IoGetCurrentIrpStackLocation(Irp);
4819     MajorFunction = IoStack->MajorFunction;
4820 
4821     switch (MajorFunction)
4822     {
4823         case IRP_MJ_CREATE:
4824         case IRP_MJ_CLOSE:
4825             DPRINT("USBH_PdoDispatch: IRP_MJ_CREATE / IRP_MJ_CLOSE (%d)\n",
4826                    MajorFunction);
4827             Status = STATUS_SUCCESS;
4828             USBH_CompleteIrp(Irp, Status);
4829             break;
4830 
4831         case IRP_MJ_DEVICE_CONTROL:
4832             ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
4833             DPRINT("USBH_PdoDispatch: IRP_MJ_DEVICE_CONTROL ControlCode - %x\n",
4834                    ControlCode);
4835 
4836             if (ControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
4837             {
4838                 Status = STATUS_NOT_SUPPORTED;
4839                 USBH_CompleteIrp(Irp, Status);
4840                 break;
4841             }
4842 
4843             if (ControlCode == IOCTL_KS_PROPERTY)
4844             {
4845                 DPRINT1("USBH_PdoDispatch: IOCTL_KS_PROPERTY FIXME\n");
4846                 DbgBreakPoint();
4847                 Status = STATUS_NOT_SUPPORTED;
4848                 USBH_CompleteIrp(Irp, Status);
4849                 break;
4850             }
4851 
4852             Status = Irp->IoStatus.Status;
4853             USBH_CompleteIrp(Irp, Status);
4854             break;
4855 
4856         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
4857             Status = USBH_PdoInternalControl(PortExtension, Irp);
4858             break;
4859 
4860         case IRP_MJ_PNP:
4861             Status = USBH_PdoPnP(PortExtension,
4862                                  Irp,
4863                                  IoStack->MinorFunction,
4864                                  &ShouldCompleteIrp);
4865 
4866             if (ShouldCompleteIrp)
4867             {
4868                 USBH_CompleteIrp(Irp, Status);
4869             }
4870 
4871             break;
4872 
4873         case IRP_MJ_POWER:
4874             Status = USBH_PdoPower(PortExtension, Irp, IoStack->MinorFunction);
4875             break;
4876 
4877         case IRP_MJ_SYSTEM_CONTROL:
4878             DPRINT1("USBH_PdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
4879             //USBH_PortSystemControl(PortExtension, Irp);
4880             Status = Irp->IoStatus.Status;
4881             USBH_CompleteIrp(Irp, Status);
4882             break;
4883 
4884         default:
4885             DPRINT("USBH_PdoDispatch: Unhandled MajorFunction - %d\n", MajorFunction);
4886             Status = Irp->IoStatus.Status;
4887             USBH_CompleteIrp(Irp, Status);
4888             break;
4889     }
4890 
4891     return Status;
4892 }
4893 
4894 NTSTATUS
4895 NTAPI
USBH_FdoDispatch(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp)4896 USBH_FdoDispatch(IN PUSBHUB_FDO_EXTENSION HubExtension,
4897                  IN PIRP Irp)
4898 {
4899     PIO_STACK_LOCATION IoStack;
4900     UCHAR MajorFunction;
4901     NTSTATUS Status;
4902 
4903     IoStack = IoGetCurrentIrpStackLocation(Irp);
4904 
4905     DPRINT("USBH_FdoDispatch: HubExtension - %p, Irp - %p, MajorFunction - %X\n",
4906            HubExtension,
4907            Irp,
4908            IoStack->MajorFunction);
4909 
4910     MajorFunction = IoStack->MajorFunction;
4911 
4912     switch (MajorFunction)
4913     {
4914         case IRP_MJ_CREATE:
4915         case IRP_MJ_CLOSE:
4916             Status = STATUS_SUCCESS;
4917             USBH_CompleteIrp(Irp, Status);
4918             break;
4919 
4920         case IRP_MJ_DEVICE_CONTROL:
4921             Status = USBH_DeviceControl(HubExtension, Irp);
4922             break;
4923 
4924         case IRP_MJ_PNP:
4925             Status = USBH_FdoPnP(HubExtension, Irp, IoStack->MinorFunction);
4926             break;
4927 
4928         case IRP_MJ_POWER:
4929             Status = USBH_FdoPower(HubExtension, Irp, IoStack->MinorFunction);
4930             break;
4931 
4932         case IRP_MJ_SYSTEM_CONTROL:
4933             DPRINT1("USBH_FdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n");
4934             /* fall through */
4935 
4936         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
4937         default:
4938             Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
4939             break;
4940     }
4941 
4942     return Status;
4943 }
4944 
4945 NTSTATUS
4946 NTAPI
USBH_AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT LowerPDO)4947 USBH_AddDevice(IN PDRIVER_OBJECT DriverObject,
4948                IN PDEVICE_OBJECT LowerPDO)
4949 {
4950     PDEVICE_OBJECT DeviceObject;
4951     NTSTATUS Status;
4952     PUSBHUB_FDO_EXTENSION HubExtension;
4953     PDEVICE_OBJECT LowerDevice;
4954 
4955     DPRINT("USBH_AddDevice: DriverObject - %p, LowerPDO - %p\n",
4956            DriverObject,
4957            LowerPDO);
4958 
4959     DeviceObject = NULL;
4960 
4961     Status = IoCreateDevice(DriverObject,
4962                             sizeof(USBHUB_FDO_EXTENSION),
4963                             NULL,
4964                             0x8600,
4965                             FILE_AUTOGENERATED_DEVICE_NAME,
4966                             FALSE,
4967                             &DeviceObject);
4968 
4969     if (!NT_SUCCESS(Status))
4970     {
4971         DPRINT1("USBH_AddDevice: IoCreateDevice() fail\n");
4972 
4973         if (DeviceObject)
4974         {
4975             IoDeleteDevice(DeviceObject);
4976         }
4977 
4978         return Status;
4979     }
4980 
4981     DPRINT("USBH_AddDevice: DeviceObject - %p\n", DeviceObject);
4982 
4983     HubExtension = DeviceObject->DeviceExtension;
4984     RtlZeroMemory(HubExtension, sizeof(USBHUB_FDO_EXTENSION));
4985 
4986     HubExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_HUB;
4987 
4988     LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, LowerPDO);
4989 
4990     if (!LowerDevice)
4991     {
4992         DPRINT1("USBH_AddDevice: IoAttachDeviceToDeviceStack() fail\n");
4993 
4994         if (DeviceObject)
4995         {
4996             IoDeleteDevice(DeviceObject);
4997         }
4998 
4999         return STATUS_UNSUCCESSFUL;
5000     }
5001 
5002     DPRINT("USBH_AddDevice: LowerDevice  - %p\n", LowerDevice);
5003 
5004     HubExtension->Common.SelfDevice = DeviceObject;
5005 
5006     HubExtension->LowerPDO = LowerPDO;
5007     HubExtension->LowerDevice = LowerDevice;
5008 
5009     KeInitializeSemaphore(&HubExtension->IdleSemaphore, 1, 1);
5010 
5011     DeviceObject->Flags |= DO_POWER_PAGABLE;
5012     DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
5013 
5014     DPRINT("USBH_AddDevice: call IoWMIRegistrationControl() UNIMPLEMENTED. FIXME\n");
5015 
5016     return Status;
5017 }
5018 
5019 VOID
5020 NTAPI
USBH_DriverUnload(IN PDRIVER_OBJECT DriverObject)5021 USBH_DriverUnload(IN PDRIVER_OBJECT DriverObject)
5022 {
5023     DPRINT("USBH_DriverUnload: UNIMPLEMENTED\n");
5024 
5025     if (GenericUSBDeviceString)
5026     {
5027         ExFreePool(GenericUSBDeviceString);
5028         GenericUSBDeviceString = NULL;
5029     }
5030 }
5031 
5032 NTSTATUS
5033 NTAPI
USBH_HubDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)5034 USBH_HubDispatch(IN PDEVICE_OBJECT DeviceObject,
5035                  IN PIRP Irp)
5036 {
5037     PCOMMON_DEVICE_EXTENSION DeviceExtension;
5038     ULONG ExtensionType;
5039     NTSTATUS Status;
5040 
5041 
5042     DeviceExtension = DeviceObject->DeviceExtension;
5043     ExtensionType = DeviceExtension->ExtensionType;
5044 
5045     if (ExtensionType == USBH_EXTENSION_TYPE_HUB)
5046     {
5047         DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
5048                DeviceObject,
5049                Irp);
5050 
5051         Status = USBH_FdoDispatch((PUSBHUB_FDO_EXTENSION)DeviceExtension, Irp);
5052     }
5053     else if (ExtensionType == USBH_EXTENSION_TYPE_PORT)
5054     {
5055         PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
5056         UCHAR MajorFunction = IoStack->MajorFunction;
5057         BOOLEAN IsDprint = TRUE;
5058 
5059         if (MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
5060         {
5061             ULONG ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
5062 
5063             if (ControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
5064             {
5065                 IsDprint = FALSE;
5066             }
5067         }
5068 
5069         if (IsDprint)
5070         {
5071             DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n",
5072                    DeviceObject,
5073                    Irp);
5074         }
5075 
5076         Status = USBH_PdoDispatch((PUSBHUB_PORT_PDO_EXTENSION)DeviceExtension, Irp);
5077     }
5078     else
5079     {
5080         DPRINT1("USBH_HubDispatch: Unknown ExtensionType - %x\n", ExtensionType);
5081         DbgBreakPoint();
5082         Status = STATUS_ASSERTION_FAILURE;
5083     }
5084 
5085     return Status;
5086 }
5087 
5088 NTSTATUS
5089 NTAPI
USBH_RegQueryGenericUSBDeviceString(PVOID USBDeviceString)5090 USBH_RegQueryGenericUSBDeviceString(PVOID USBDeviceString)
5091 {
5092     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
5093 
5094     DPRINT("USBH_RegQueryGenericUSBDeviceString ... \n");
5095 
5096     RtlZeroMemory(QueryTable, sizeof(QueryTable));
5097 
5098     QueryTable[0].QueryRoutine = USBH_GetConfigValue;
5099     QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
5100     QueryTable[0].Name = L"GenericUSBDeviceString";
5101     QueryTable[0].EntryContext = USBDeviceString;
5102     QueryTable[0].DefaultType = REG_NONE;
5103     QueryTable[0].DefaultData = 0;
5104     QueryTable[0].DefaultLength = 0;
5105 
5106     return RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
5107                                   L"usbflags",
5108                                   QueryTable,
5109                                   NULL,
5110                                   NULL);
5111 }
5112 
5113 NTSTATUS
5114 NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)5115 DriverEntry(IN PDRIVER_OBJECT DriverObject,
5116             IN PUNICODE_STRING RegistryPath)
5117 {
5118     DPRINT("USBHUB: DriverEntry - %wZ\n", RegistryPath);
5119 
5120     DriverObject->DriverExtension->AddDevice = USBH_AddDevice;
5121     DriverObject->DriverUnload = USBH_DriverUnload;
5122 
5123     DriverObject->MajorFunction[IRP_MJ_CREATE] = USBH_HubDispatch;
5124     DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBH_HubDispatch;
5125 
5126     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBH_HubDispatch;
5127     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBH_HubDispatch;
5128 
5129     DriverObject->MajorFunction[IRP_MJ_PNP] = USBH_HubDispatch;
5130     DriverObject->MajorFunction[IRP_MJ_POWER] = USBH_HubDispatch;
5131     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBH_HubDispatch;
5132 
5133     USBH_RegQueryGenericUSBDeviceString(&GenericUSBDeviceString);
5134 
5135     return STATUS_SUCCESS;
5136 }
5137 
5138