xref: /reactos/drivers/usb/usbhub/power.c (revision 611d925d)
1 /*
2  * PROJECT:     ReactOS USB Hub Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBHub power handling 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_POWER
14 #include "dbg_uhub.h"
15 
16 VOID
17 NTAPI
USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp,IN NTSTATUS NtStatus)18 USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
19                       IN PIRP Irp,
20                       IN NTSTATUS NtStatus)
21 {
22     DPRINT("USBH_CompletePowerIrp: HubExtension - %p, Irp - %p, NtStatus - %lX\n",
23            HubExtension,
24            Irp,
25            NtStatus);
26 
27     Irp->IoStatus.Status = NtStatus;
28 
29     PoStartNextPowerIrp(Irp);
30 
31     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
32     {
33         KeSetEvent(&HubExtension->PendingRequestEvent,
34                    EVENT_INCREMENT,
35                    FALSE);
36     }
37 
38     IoCompleteRequest(Irp, IO_NO_INCREMENT);
39 }
40 
41 VOID
42 NTAPI
USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp)43 USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
44                       IN PIRP Irp)
45 {
46     DPRINT("USBH_HubCancelWakeIrp: HubExtension - %p, Irp - %p\n",
47            HubExtension,
48            Irp);
49 
50     IoCancelIrp(Irp);
51 
52     if (InterlockedExchange((PLONG)&HubExtension->FdoWaitWakeLock, 1))
53     {
54         PoStartNextPowerIrp(Irp);
55         Irp->IoStatus.Status = STATUS_CANCELLED;
56         IoCompleteRequest(Irp, IO_NO_INCREMENT);
57     }
58 }
59 
60 VOID
61 NTAPI
USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)62 USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject,
63                                    IN UCHAR MinorFunction,
64                                    IN POWER_STATE PowerState,
65                                    IN PVOID Context,
66                                    IN PIO_STATUS_BLOCK IoStatus)
67 {
68     DPRINT("USBH_HubESDRecoverySetD3Completion ... \n");
69 
70     KeSetEvent((PRKEVENT)Context,
71                EVENT_INCREMENT,
72                FALSE);
73 }
74 
75 NTSTATUS
76 NTAPI
USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension)77 USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension)
78 {
79     PUSBHUB_FDO_EXTENSION RootHubDevExt;
80     NTSTATUS Status;
81     KEVENT Event;
82     POWER_STATE PowerState;
83 
84     DPRINT("USBH_HubSetD0: HubExtension - %p\n", HubExtension);
85 
86     RootHubDevExt = USBH_GetRootHubExtension(HubExtension);
87 
88     if (RootHubDevExt->SystemPowerState.SystemState != PowerSystemWorking)
89     {
90         Status = STATUS_INVALID_DEVICE_STATE;
91         return Status;
92     }
93 
94     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
95     {
96         DPRINT("USBH_HubSetD0: HubFlags - %lX\n", HubExtension->HubFlags);
97 
98         KeWaitForSingleObject(&HubExtension->IdleEvent,
99                               Suspended,
100                               KernelMode,
101                               FALSE,
102                               NULL);
103     }
104 
105     KeInitializeEvent(&Event, NotificationEvent, FALSE);
106 
107     PowerState.DeviceState = PowerDeviceD0;
108 
109     Status = PoRequestPowerIrp(HubExtension->LowerPDO,
110                                IRP_MN_SET_POWER,
111                                PowerState,
112                                USBH_HubESDRecoverySetD3Completion,
113                                &Event,
114                                NULL);
115 
116     if (Status == STATUS_PENDING)
117     {
118        Status = KeWaitForSingleObject(&Event,
119                                       Suspended,
120                                       KernelMode,
121                                       FALSE,
122                                       NULL);
123     }
124 
125     while (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAKEUP_START)
126     {
127         USBH_Wait(10);
128     }
129 
130     return Status;
131 }
132 
133 VOID
134 NTAPI
USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)135 USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
136                               IN PVOID Context)
137 {
138     PUSBHUB_IDLE_PORT_CANCEL_CONTEXT WorkItemIdlePower;
139     PIRP Irp;
140 
141     DPRINT("USBH_IdleCancelPowerHubWorker: ... \n");
142 
143     WorkItemIdlePower = Context;
144 
145     if (HubExtension &&
146         HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
147         HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
148     {
149         USBH_HubSetD0(HubExtension);
150     }
151 
152     Irp = WorkItemIdlePower->Irp;
153     Irp->IoStatus.Status = STATUS_CANCELLED;
154 
155     IoCompleteRequest(Irp, IO_NO_INCREMENT);
156 }
157 
158 VOID
159 NTAPI
USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PLIST_ENTRY ListIrps)160 USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
161                           IN PLIST_ENTRY ListIrps)
162 {
163     PDEVICE_OBJECT PortDevice;
164     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
165     USHORT NumPorts;
166     USHORT Port;
167     PIRP WakeIrp;
168     KIRQL OldIrql;
169 
170     DPRINT("USBH_HubQueuePortWakeIrps ... \n");
171 
172     NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
173 
174     InitializeListHead(ListIrps);
175 
176     IoAcquireCancelSpinLock(&OldIrql);
177 
178     for (Port = 0; Port < NumPorts; ++Port)
179     {
180         PortDevice = HubExtension->PortData[Port].DeviceObject;
181 
182         if (PortDevice)
183         {
184             PortExtension = PortDevice->DeviceExtension;
185 
186             WakeIrp = PortExtension->PdoWaitWakeIrp;
187             PortExtension->PdoWaitWakeIrp = NULL;
188 
189             if (WakeIrp)
190             {
191                 DPRINT1("USBH_HubQueuePortWakeIrps: UNIMPLEMENTED. FIXME\n");
192                 DbgBreakPoint();
193             }
194         }
195     }
196 
197     IoReleaseCancelSpinLock(OldIrql);
198 }
199 
200 VOID
201 NTAPI
USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PLIST_ENTRY ListIrps,IN NTSTATUS NtStatus)202 USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
203                                    IN PLIST_ENTRY ListIrps,
204                                    IN NTSTATUS NtStatus)
205 {
206     DPRINT("USBH_HubCompleteQueuedPortWakeIrps ... \n");
207 
208     while (!IsListEmpty(ListIrps))
209     {
210         DPRINT1("USBH_HubCompleteQueuedPortWakeIrps: UNIMPLEMENTED. FIXME\n");
211         DbgBreakPoint();
212     }
213 }
214 
215 VOID
216 NTAPI
USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,IN NTSTATUS NtStatus)217 USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
218                              IN NTSTATUS NtStatus)
219 {
220     LIST_ENTRY ListIrps;
221 
222     DPRINT("USBH_HubCompletePortWakeIrps: NtStatus - %x\n", NtStatus);
223 
224     if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
225     {
226         USBH_HubQueuePortWakeIrps(HubExtension, &ListIrps);
227 
228         USBH_HubCompleteQueuedPortWakeIrps(HubExtension,
229                                            &ListIrps,
230                                            NtStatus);
231     }
232 }
233 
234 VOID
235 NTAPI
USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)236 USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject,
237                               IN UCHAR MinorFunction,
238                               IN POWER_STATE PowerState,
239                               IN PVOID Context,
240                               IN PIO_STATUS_BLOCK IoStatus)
241 {
242     PUSBHUB_FDO_EXTENSION HubExtension;
243 
244     DPRINT("USBH_FdoPoRequestD0Completion ... \n");
245 
246     HubExtension = Context;
247 
248     USBH_HubCompletePortWakeIrps(HubExtension, STATUS_SUCCESS);
249 
250     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAKEUP_START;
251 
252     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
253     {
254         KeSetEvent(&HubExtension->PendingRequestEvent,
255                    EVENT_INCREMENT,
256                    FALSE);
257     }
258 }
259 
260 VOID
261 NTAPI
USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PVOID Context)262 USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
263                                 IN PVOID Context)
264 {
265     DPRINT1("USBH_CompletePortWakeIrpsWorker: UNIMPLEMENTED. FIXME\n");
266     DbgBreakPoint();
267 }
268 
269 NTSTATUS
270 NTAPI
USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)271 USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject,
272                           IN PIRP Irp,
273                           IN PVOID Context)
274 {
275     PUSBHUB_FDO_EXTENSION HubExtension;
276     NTSTATUS Status;
277     KIRQL OldIrql;
278     POWER_STATE PowerState;
279     PIRP WakeIrp;
280 
281     DPRINT("USBH_FdoWWIrpIoCompletion: DeviceObject - %p, Irp - %p\n",
282             DeviceObject,
283             Irp);
284 
285     HubExtension = Context;
286 
287     Status = Irp->IoStatus.Status;
288 
289     IoAcquireCancelSpinLock(&OldIrql);
290 
291     HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
292 
293     WakeIrp = InterlockedExchangePointer((PVOID *)&HubExtension->PendingWakeIrp,
294                                          NULL);
295 
296     if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
297     {
298         KeSetEvent(&HubExtension->PendingRequestEvent,
299                    EVENT_INCREMENT,
300                    FALSE);
301     }
302 
303     IoReleaseCancelSpinLock(OldIrql);
304 
305     DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
306 
307     if (!NT_SUCCESS(Status))
308     {
309         DPRINT1("USBH_FdoWWIrpIoCompletion: DbgBreakPoint() \n");
310         DbgBreakPoint();
311     }
312     else
313     {
314         PowerState.DeviceState = PowerDeviceD0;
315 
316         HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAKEUP_START;
317         InterlockedIncrement(&HubExtension->PendingRequestCount);
318 
319         Status = STATUS_SUCCESS;
320 
321         PoRequestPowerIrp(HubExtension->LowerPDO,
322                           IRP_MN_SET_POWER,
323                           PowerState,
324                           USBH_FdoPoRequestD0Completion,
325                           (PVOID)HubExtension,
326                           NULL);
327     }
328 
329     if (!WakeIrp)
330     {
331         if (!InterlockedExchange(&HubExtension->FdoWaitWakeLock, 1))
332         {
333             Status = STATUS_MORE_PROCESSING_REQUIRED;
334         }
335     }
336 
337     DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
338 
339     if (Status != STATUS_MORE_PROCESSING_REQUIRED)
340     {
341         PoStartNextPowerIrp(Irp);
342     }
343 
344     return Status;
345 }
346 
347 NTSTATUS
348 NTAPI
USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)349 USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
350                         IN PIRP Irp,
351                         IN PVOID Context)
352 {
353     PUSBHUB_FDO_EXTENSION HubExtension;
354     PIO_STACK_LOCATION IoStack;
355     DEVICE_POWER_STATE OldDeviceState;
356     NTSTATUS Status;
357     POWER_STATE PowerState;
358 
359     DPRINT("USBH_PowerIrpCompletion: DeviceObject - %p, Irp - %p\n",
360            DeviceObject,
361            Irp);
362 
363     HubExtension = Context;
364 
365     IoStack = IoGetCurrentIrpStackLocation(Irp);
366     PowerState = IoStack->Parameters.Power.State;
367 
368     Status = Irp->IoStatus.Status;
369     DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
370 
371     if (!NT_SUCCESS(Status))
372     {
373         if (PowerState.DeviceState == PowerDeviceD0)
374         {
375             PoStartNextPowerIrp(Irp);
376             HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
377         }
378     }
379     else if (PowerState.DeviceState == PowerDeviceD0)
380     {
381         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
382 
383         OldDeviceState = HubExtension->CurrentPowerState.DeviceState;
384         HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
385 
386         DPRINT("USBH_PowerIrpCompletion: OldDeviceState - %x\n", OldDeviceState);
387 
388         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_HIBERNATE_STATE)
389         {
390             DPRINT1("USBH_PowerIrpCompletion: USBHUB_FDO_FLAG_HIBERNATE_STATE. FIXME\n");
391             DbgBreakPoint();
392         }
393 
394         HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HIBERNATE_STATE;
395 
396         if (OldDeviceState == PowerDeviceD3)
397         {
398             DPRINT1("USBH_PowerIrpCompletion: PowerDeviceD3. FIXME\n");
399             DbgBreakPoint();
400         }
401 
402         if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) &&
403             HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)
404         {
405             USBH_SubmitStatusChangeTransfer(HubExtension);
406         }
407 
408         DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
409 
410         if (Status != STATUS_MORE_PROCESSING_REQUIRED)
411         {
412             PoStartNextPowerIrp(Irp);
413             return Status;
414         }
415     }
416 
417     return Status;
418 }
419 
420 VOID
421 NTAPI
USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)422 USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
423                                  IN UCHAR MinorFunction,
424                                  IN POWER_STATE PowerState,
425                                  IN PVOID Context,
426                                  IN PIO_STATUS_BLOCK IoStatus)
427 {
428     PUSBHUB_FDO_EXTENSION Extension;
429     PUSBHUB_FDO_EXTENSION HubExtension = NULL;
430     PIRP PowerIrp;
431     PIO_STACK_LOCATION IoStack;
432 
433     DPRINT("USBH_FdoDeferPoRequestCompletion ... \n");
434 
435     Extension = Context;
436 
437     PowerIrp = Extension->PowerIrp;
438 
439     if (Extension->Common.ExtensionType == USBH_EXTENSION_TYPE_HUB)
440     {
441         HubExtension = Context;
442     }
443 
444     IoStack = IoGetCurrentIrpStackLocation(PowerIrp);
445 
446     if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking &&
447         HubExtension && HubExtension->LowerPDO == HubExtension->RootHubPdo)
448     {
449         HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
450         USBH_CheckIdleDeferred(HubExtension);
451     }
452 
453     IoCopyCurrentIrpStackLocationToNext(PowerIrp);
454     PoStartNextPowerIrp(PowerIrp);
455     PoCallDriver(Extension->LowerDevice, PowerIrp);
456 }
457 
458 NTSTATUS
459 NTAPI
USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension,IN PIRP Irp,IN UCHAR Minor)460 USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension,
461               IN PIRP Irp,
462               IN UCHAR Minor)
463 {
464     NTSTATUS Status;
465     PIO_STACK_LOCATION IoStack;
466     POWER_STATE PowerState;
467     POWER_STATE DevicePwrState;
468     BOOLEAN IsAllPortsD3;
469     PUSBHUB_PORT_DATA PortData;
470     PDEVICE_OBJECT PdoDevice;
471     PUSBHUB_PORT_PDO_EXTENSION PortExtension;
472     ULONG Port;
473 
474     DPRINT_PWR("USBH_FdoPower: HubExtension - %p, Irp - %p, Minor - %X\n",
475                HubExtension,
476                Irp,
477                Minor);
478 
479     switch (Minor)
480     {
481         case IRP_MN_WAIT_WAKE:
482             DPRINT_PWR("USBH_FdoPower: IRP_MN_WAIT_WAKE\n");
483 
484             IoCopyCurrentIrpStackLocationToNext(Irp);
485 
486             IoSetCompletionRoutine(Irp,
487                                    USBH_FdoWWIrpIoCompletion,
488                                    HubExtension,
489                                    TRUE,
490                                    TRUE,
491                                    TRUE);
492 
493             PoStartNextPowerIrp(Irp);
494             IoMarkIrpPending(Irp);
495             PoCallDriver(HubExtension->LowerDevice, Irp);
496 
497             return STATUS_PENDING;
498 
499         case IRP_MN_POWER_SEQUENCE:
500             DPRINT_PWR("USBH_FdoPower: IRP_MN_POWER_SEQUENCE\n");
501             break;
502 
503         case IRP_MN_SET_POWER:
504             DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER\n");
505 
506             IoStack = IoGetCurrentIrpStackLocation(Irp);
507             DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER/DevicePowerState\n");
508             PowerState = IoStack->Parameters.Power.State;
509 
510             if (IoStack->Parameters.Power.Type == DevicePowerState)
511             {
512                 DPRINT_PWR("USBH_FdoPower: PowerState - %x\n",
513                            PowerState.DeviceState);
514 
515                 if (HubExtension->CurrentPowerState.DeviceState == PowerState.DeviceState)
516                 {
517                     IoCopyCurrentIrpStackLocationToNext(Irp);
518 
519                     PoStartNextPowerIrp(Irp);
520                     IoMarkIrpPending(Irp);
521                     PoCallDriver(HubExtension->LowerDevice, Irp);
522 
523                     return STATUS_PENDING;
524                 }
525 
526                 switch (PowerState.DeviceState)
527                 {
528                     case PowerDeviceD0:
529                         if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_SET_D0_STATE))
530                         {
531                             HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
532                                                         USBHUB_FDO_FLAG_DEVICE_STOPPING);
533 
534                             HubExtension->HubFlags |= USBHUB_FDO_FLAG_SET_D0_STATE;
535 
536                             IoCopyCurrentIrpStackLocationToNext(Irp);
537 
538                             IoSetCompletionRoutine(Irp,
539                                                    USBH_PowerIrpCompletion,
540                                                    HubExtension,
541                                                    TRUE,
542                                                    TRUE,
543                                                    TRUE);
544                         }
545                         else
546                         {
547                             IoCopyCurrentIrpStackLocationToNext(Irp);
548                             PoStartNextPowerIrp(Irp);
549                         }
550 
551                         IoMarkIrpPending(Irp);
552                         PoCallDriver(HubExtension->LowerDevice, Irp);
553                         return STATUS_PENDING;
554 
555                     case PowerDeviceD1:
556                     case PowerDeviceD2:
557                     case PowerDeviceD3:
558                         if (HubExtension->ResetRequestCount)
559                         {
560                             IoCancelIrp(HubExtension->ResetPortIrp);
561 
562                             KeWaitForSingleObject(&HubExtension->ResetEvent,
563                                                   Executive,
564                                                   KernelMode,
565                                                   FALSE,
566                                                   NULL);
567                         }
568 
569                         if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
570                         {
571                             HubExtension->HubFlags |= (USBHUB_FDO_FLAG_NOT_D0_STATE |
572                                                        USBHUB_FDO_FLAG_DEVICE_STOPPING);
573 
574                             IoCancelIrp(HubExtension->SCEIrp);
575 
576                             KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
577                                                   Executive,
578                                                   KernelMode,
579                                                   FALSE,
580                                                   NULL);
581                         }
582 
583                         HubExtension->CurrentPowerState.DeviceState = PowerState.DeviceState;
584 
585                         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE &&
586                             USBH_CheckIdleAbort(HubExtension, TRUE, TRUE) == TRUE)
587                         {
588                             HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
589                                                         USBHUB_FDO_FLAG_DEVICE_STOPPING);
590 
591                             HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
592 
593                             USBH_SubmitStatusChangeTransfer(HubExtension);
594 
595                             PoStartNextPowerIrp(Irp);
596 
597                             Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
598                             IoCompleteRequest(Irp, IO_NO_INCREMENT);
599 
600                             HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
601 
602                             KeReleaseSemaphore(&HubExtension->IdleSemaphore,
603                                                LOW_REALTIME_PRIORITY,
604                                                1,
605                                                FALSE);
606 
607                             return STATUS_UNSUCCESSFUL;
608                         }
609 
610                         IoCopyCurrentIrpStackLocationToNext(Irp);
611 
612                         IoSetCompletionRoutine(Irp,
613                                                USBH_PowerIrpCompletion,
614                                                HubExtension,
615                                                TRUE,
616                                                TRUE,
617                                                TRUE);
618 
619                         PoStartNextPowerIrp(Irp);
620                         IoMarkIrpPending(Irp);
621                         PoCallDriver(HubExtension->LowerDevice, Irp);
622 
623                         if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE)
624                         {
625                             HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
626 
627                             KeReleaseSemaphore(&HubExtension->IdleSemaphore,
628                                                LOW_REALTIME_PRIORITY,
629                                                1,
630                                                FALSE);
631                         }
632 
633                         return STATUS_PENDING;
634 
635                     default:
636                         DPRINT1("USBH_FdoPower: Unsupported PowerState.DeviceState\n");
637                         DbgBreakPoint();
638                         break;
639                 }
640             }
641             else
642             {
643                 if (PowerState.SystemState != PowerSystemWorking)
644                 {
645                     USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState =
646                                                             PowerState.SystemState;
647                 }
648 
649                 if (PowerState.SystemState == PowerSystemHibernate)
650                 {
651                     HubExtension->HubFlags |= USBHUB_FDO_FLAG_HIBERNATE_STATE;
652                 }
653 
654                 PortData = HubExtension->PortData;
655 
656                 IsAllPortsD3 = TRUE;
657 
658                 if (PortData && HubExtension->HubDescriptor)
659                 {
660                     for (Port = 0;
661                          Port < HubExtension->HubDescriptor->bNumberOfPorts;
662                          Port++)
663                     {
664                         PdoDevice = PortData[Port].DeviceObject;
665 
666                         if (PdoDevice)
667                         {
668                             PortExtension = PdoDevice->DeviceExtension;
669 
670                             if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD3)
671                             {
672                                 IsAllPortsD3 = FALSE;
673                                 break;
674                             }
675                         }
676                     }
677                 }
678 
679                 if (PowerState.SystemState == PowerSystemWorking)
680                 {
681                     DevicePwrState.DeviceState = PowerDeviceD0;
682                 }
683                 else if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP ||
684                          !IsAllPortsD3)
685                 {
686                     DevicePwrState.DeviceState = HubExtension->DeviceState[PowerState.SystemState];
687 
688                     if (DevicePwrState.DeviceState == PowerDeviceUnspecified)
689                     {
690                         goto Exit;
691                     }
692                 }
693                 else
694                 {
695                     DevicePwrState.DeviceState = PowerDeviceD3;
696                 }
697 
698                 if (DevicePwrState.DeviceState != HubExtension->CurrentPowerState.DeviceState &&
699                     HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
700                 {
701                     HubExtension->PowerIrp = Irp;
702 
703                     IoMarkIrpPending(Irp);
704 
705                     if (PoRequestPowerIrp(HubExtension->LowerPDO,
706                                           IRP_MN_SET_POWER,
707                                           DevicePwrState,
708                                           USBH_FdoDeferPoRequestCompletion,
709                                           (PVOID)HubExtension,
710                                           NULL) == STATUS_PENDING)
711                     {
712                         return STATUS_PENDING;
713                     }
714 
715                     IoCopyCurrentIrpStackLocationToNext(Irp);
716                     PoStartNextPowerIrp(Irp);
717                     PoCallDriver(HubExtension->LowerDevice, Irp);
718 
719                     return STATUS_PENDING;
720                 }
721 
722             Exit:
723 
724                 HubExtension->SystemPowerState.SystemState = PowerState.SystemState;
725 
726                 if (PowerState.SystemState == PowerSystemWorking)
727                 {
728                     USBH_CheckIdleDeferred(HubExtension);
729                 }
730 
731                 IoCopyCurrentIrpStackLocationToNext(Irp);
732                 PoStartNextPowerIrp(Irp);
733 
734                 return PoCallDriver(HubExtension->LowerDevice, Irp);
735             }
736 
737             break;
738 
739         case IRP_MN_QUERY_POWER:
740             DPRINT_PWR("USBH_FdoPower: IRP_MN_QUERY_POWER\n");
741             break;
742 
743         default:
744             DPRINT1("USBH_FdoPower: unknown IRP_MN_POWER!\n");
745             break;
746     }
747 
748     IoCopyCurrentIrpStackLocationToNext(Irp);
749     PoStartNextPowerIrp(Irp);
750     Status = PoCallDriver(HubExtension->LowerDevice, Irp);
751 
752     return Status;
753 }
754 
755 NTSTATUS
756 NTAPI
USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,IN PIRP Irp,IN UCHAR Minor)757 USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
758               IN PIRP Irp,
759               IN UCHAR Minor)
760 {
761     NTSTATUS Status = Irp->IoStatus.Status;
762 
763     DPRINT_PWR("USBH_FdoPower: PortExtension - %p, Irp - %p, Minor - %X\n",
764                PortExtension,
765                Irp,
766                Minor);
767 
768     switch (Minor)
769     {
770       case IRP_MN_WAIT_WAKE:
771           DPRINT_PWR("USBHUB_PdoPower: IRP_MN_WAIT_WAKE\n");
772           PoStartNextPowerIrp(Irp);
773           break;
774 
775       case IRP_MN_POWER_SEQUENCE:
776           DPRINT_PWR("USBHUB_PdoPower: IRP_MN_POWER_SEQUENCE\n");
777           PoStartNextPowerIrp(Irp);
778           break;
779 
780       case IRP_MN_SET_POWER:
781           DPRINT_PWR("USBHUB_PdoPower: IRP_MN_SET_POWER\n");
782           PoStartNextPowerIrp(Irp);
783           break;
784 
785       case IRP_MN_QUERY_POWER:
786           DPRINT_PWR("USBHUB_PdoPower: IRP_MN_QUERY_POWER\n");
787           PoStartNextPowerIrp(Irp);
788           break;
789 
790       default:
791           DPRINT1("USBHUB_PdoPower: unknown IRP_MN_POWER!\n");
792           PoStartNextPowerIrp(Irp);
793           break;
794     }
795 
796     Irp->IoStatus.Status = Status;
797     Irp->IoStatus.Information = 0;
798     IoCompleteRequest(Irp, IO_NO_INCREMENT);
799 
800     return Status;
801 }
802