xref: /reactos/drivers/usb/usbport/power.c (revision 9393fc32)
1 /*
2  * PROJECT:     ReactOS USB Port Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBPort power handling functions
5  * COPYRIGHT:   Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbport.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 VOID
14 NTAPI
15 USBPORT_CompletePdoWaitWake(IN PDEVICE_OBJECT FdoDevice)
16 {
17     PUSBPORT_DEVICE_EXTENSION FdoExtension;
18     PDEVICE_OBJECT PdoDevice;
19     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
20     PIRP Irp;
21     KIRQL OldIrql;
22 
23     DPRINT("USBPORT_CompletePdoWaitWake: ... \n");
24 
25     FdoExtension = FdoDevice->DeviceExtension;
26     PdoDevice = FdoExtension->RootHubPdo;
27     PdoExtension = PdoDevice->DeviceExtension;
28 
29     KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql);
30 
31     Irp = PdoExtension->WakeIrp;
32 
33     if (Irp && IoSetCancelRoutine(Irp, NULL))
34     {
35         PdoExtension->WakeIrp = NULL;
36         KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
37 
38         DPRINT("USBPORT_CompletePdoWaitWake: Complete Irp - %p\n", Irp);
39 
40         Irp->IoStatus.Status = STATUS_SUCCESS;
41         Irp->IoStatus.Information = 0;
42         IoCompleteRequest(Irp, IO_NO_INCREMENT);
43 
44         return;
45     }
46 
47     KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
48 }
49 
50 VOID
51 NTAPI
52 USBPORT_HcWakeDpc(IN PRKDPC Dpc,
53                   IN PVOID DeferredContext,
54                   IN PVOID SystemArgument1,
55                   IN PVOID SystemArgument2)
56 {
57     DPRINT("USBPORT_HcWakeDpc: ... \n");
58     USBPORT_CompletePdoWaitWake((PDEVICE_OBJECT)DeferredContext);
59 }
60 
61 VOID
62 NTAPI
63 USBPORT_HcQueueWakeDpc(IN PDEVICE_OBJECT FdoDevice)
64 {
65     PUSBPORT_DEVICE_EXTENSION FdoExtension;
66 
67     DPRINT("USBPORT_HcQueueWakeDpc: ... \n");
68 
69     FdoExtension = FdoDevice->DeviceExtension;
70     KeInsertQueueDpc(&FdoExtension->HcWakeDpc, NULL, NULL);
71 }
72 
73 VOID
74 NTAPI
75 USBPORT_CompletePendingIdleIrp(IN PDEVICE_OBJECT PdoDevice)
76 {
77     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
78     PDEVICE_OBJECT FdoDevice;
79     PUSBPORT_DEVICE_EXTENSION FdoExtension;
80     PIRP Irp;
81 
82     DPRINT("USBPORT_CompletePendingIdleIrp: ... \n");
83 
84     PdoExtension = PdoDevice->DeviceExtension;
85     FdoDevice = PdoExtension->FdoDevice;
86     FdoExtension = FdoDevice->DeviceExtension;
87 
88     Irp = IoCsqRemoveNextIrp(&FdoExtension->IdleIoCsq, 0);
89 
90     if (Irp)
91     {
92         InterlockedDecrement(&FdoExtension->IdleLockCounter);
93 
94         DPRINT("USBPORT_CompletePendingIdleIrp: Complete Irp - %p\n", Irp);
95 
96         Irp->IoStatus.Status = STATUS_CANCELLED;
97         Irp->IoStatus.Information = 0;
98         IoCompleteRequest(Irp, IO_NO_INCREMENT);
99     }
100 }
101 
102 VOID
103 NTAPI
104 USBPORT_DoSetPowerD0(IN PDEVICE_OBJECT FdoDevice)
105 {
106     DPRINT("USBPORT_DoSetPowerD0: FIXME!\n");
107     return;
108 }
109 
110 VOID
111 NTAPI
112 USBPORT_SuspendController(IN PDEVICE_OBJECT FdoDevice)
113 {
114     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
115     PUSBPORT_REGISTRATION_PACKET Packet;
116 
117     DPRINT1("USBPORT_SuspendController \n");
118 
119     FdoExtension = FdoDevice->DeviceExtension;
120     Packet = &FdoExtension->MiniPortInterface->Packet;
121 
122     FdoExtension->TimerFlags |= USBPORT_TMFLAG_RH_SUSPENDED;
123 
124     USBPORT_FlushController(FdoDevice);
125 
126     if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)
127     {
128         return;
129     }
130 
131     FdoExtension->TimerFlags |= USBPORT_TMFLAG_HC_SUSPENDED;
132 
133     if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED)
134     {
135         FdoExtension->MiniPortFlags |= USBPORT_MPFLAG_SUSPENDED;
136 
137         USBPORT_Wait(FdoDevice, 10);
138         Packet->SuspendController(FdoExtension->MiniPortExt);
139     }
140 
141     FdoExtension->Flags |= USBPORT_FLAG_HC_SUSPEND;
142 }
143 
144 NTSTATUS
145 NTAPI
146 USBPORT_ResumeController(IN PDEVICE_OBJECT FdoDevice)
147 {
148     NTSTATUS Status = STATUS_UNSUCCESSFUL;
149     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
150     PUSBPORT_REGISTRATION_PACKET Packet;
151     KIRQL OldIrql;
152     MPSTATUS MpStatus;
153 
154     DPRINT1("USBPORT_ResumeController: ... \n");
155 
156     FdoExtension = FdoDevice->DeviceExtension;
157     Packet = &FdoExtension->MiniPortInterface->Packet;
158 
159     if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND))
160     {
161         return Status;
162     }
163 
164     KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql);
165 
166     FdoExtension->TimerFlags &= ~(USBPORT_TMFLAG_HC_SUSPENDED |
167                                   USBPORT_TMFLAG_RH_SUSPENDED);
168 
169     KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql);
170 
171     if (!(FdoExtension->MiniPortFlags & USBPORT_MPFLAG_SUSPENDED))
172     {
173         FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND;
174         return Status;
175     }
176 
177     FdoExtension->MiniPortFlags &= ~USBPORT_MPFLAG_SUSPENDED;
178 
179     if (!Packet->ResumeController(FdoExtension->MiniPortExt))
180     {
181         Status = USBPORT_Wait(FdoDevice, 100);
182 
183         FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND;
184         return Status;
185     }
186 
187     KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql);
188     FdoExtension->TimerFlags |= (USBPORT_TMFLAG_HC_SUSPENDED |
189                                  USBPORT_TMFLAG_HC_RESUME);
190     KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql);
191 
192     USBPORT_MiniportInterrupts(FdoDevice, FALSE);
193 
194     Packet->StopController(FdoExtension->MiniPortExt, 1);
195 
196     USBPORT_NukeAllEndpoints(FdoDevice);
197 
198     RtlZeroMemory(FdoExtension->MiniPortExt, Packet->MiniPortExtensionSize);
199 
200     RtlZeroMemory((PVOID)FdoExtension->UsbPortResources.StartVA,
201                   Packet->MiniPortResourcesSize);
202 
203     FdoExtension->UsbPortResources.IsChirpHandled = TRUE;
204 
205     MpStatus = Packet->StartController(FdoExtension->MiniPortExt,
206                                        &FdoExtension->UsbPortResources);
207 
208     FdoExtension->UsbPortResources.IsChirpHandled = FALSE;
209 
210     if (!MpStatus)
211     {
212         USBPORT_MiniportInterrupts(FdoDevice, TRUE);
213     }
214 
215     KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql);
216 
217     FdoExtension->TimerFlags &= ~(USBPORT_TMFLAG_HC_SUSPENDED |
218                                   USBPORT_TMFLAG_HC_RESUME |
219                                   USBPORT_TMFLAG_RH_SUSPENDED);
220 
221     KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql);
222 
223     Status = USBPORT_Wait(FdoDevice, 100);
224 
225     FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND;
226 
227     return Status;
228 }
229 
230 NTSTATUS
231 NTAPI
232 USBPORT_PdoDevicePowerState(IN PDEVICE_OBJECT PdoDevice,
233                             IN PIRP Irp)
234 {
235     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
236     PDEVICE_OBJECT FdoDevice;
237     PUSBPORT_DEVICE_EXTENSION FdoExtension;
238     PIO_STACK_LOCATION IoStack;
239     NTSTATUS Status = STATUS_SUCCESS;
240     POWER_STATE State;
241 
242     PdoExtension = PdoDevice->DeviceExtension;
243     FdoDevice = PdoExtension->FdoDevice;
244     FdoExtension = FdoDevice->DeviceExtension;
245     IoStack = IoGetCurrentIrpStackLocation(Irp);
246 
247     State = IoStack->Parameters.Power.State;
248 
249     DPRINT1("USBPORT_PdoDevicePowerState: Irp - %p, State - %x\n",
250             Irp,
251             State.DeviceState);
252 
253     if (State.DeviceState == PowerDeviceD0)
254     {
255         if (FdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0)
256         {
257             // FIXME FdoExtension->Flags
258             while (FdoExtension->SetPowerLockCounter)
259             {
260                 USBPORT_Wait(FdoDevice, 10);
261             }
262 
263             USBPORT_ResumeController(FdoDevice);
264 
265             PdoExtension->CommonExtension.DevicePowerState = PowerDeviceD0;
266 
267             USBPORT_CompletePdoWaitWake(FdoDevice);
268             USBPORT_CompletePendingIdleIrp(PdoDevice);
269         }
270         else
271         {
272             DPRINT1("USBPORT_PdoDevicePowerState: FdoExtension->Flags - %lx\n",
273                     FdoExtension->Flags);
274 
275             DbgBreakPoint();
276             Status = STATUS_UNSUCCESSFUL;
277         }
278     }
279     else if (State.DeviceState  == PowerDeviceD1 ||
280              State.DeviceState  == PowerDeviceD2 ||
281              State.DeviceState  == PowerDeviceD3)
282     {
283         FdoExtension->TimerFlags |= USBPORT_TMFLAG_WAKE;
284         USBPORT_SuspendController(FdoDevice);
285         PdoExtension->CommonExtension.DevicePowerState = State.DeviceState;
286     }
287 
288     return Status;
289 }
290 
291 VOID
292 NTAPI
293 USBPORT_CancelPendingWakeIrp(IN PDEVICE_OBJECT PdoDevice,
294                              IN PIRP Irp)
295 {
296     PUSBPORT_DEVICE_EXTENSION FdoExtension;
297     KIRQL OldIrql;
298     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
299 
300     DPRINT("USBPORT_CancelPendingWakeIrp: ... \n");
301 
302     IoReleaseCancelSpinLock(Irp->CancelIrql);
303     PdoExtension = PdoDevice->DeviceExtension;
304     FdoExtension = PdoExtension->FdoDevice->DeviceExtension;
305 
306     KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql);
307 
308     if (PdoExtension->WakeIrp == Irp)
309     {
310         PdoExtension->WakeIrp = NULL;
311     }
312 
313     KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
314 
315     Irp->IoStatus.Status = STATUS_CANCELLED;
316     Irp->IoStatus.Information = 0;
317     IoCompleteRequest(Irp, IO_NO_INCREMENT);
318 }
319 
320 NTSTATUS
321 NTAPI
322 USBPORT_PdoPower(IN PDEVICE_OBJECT PdoDevice,
323                  IN PIRP Irp)
324 {
325     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
326     PDEVICE_OBJECT FdoDevice;
327     PIO_STACK_LOCATION IoStack;
328     PUSBPORT_DEVICE_EXTENSION FdoExtension;
329     NTSTATUS Status;
330     KIRQL OldIrql;
331 
332     DPRINT("USBPORT_PdoPower: Irp - %p\n", Irp);
333 
334     PdoExtension = PdoDevice->DeviceExtension;
335     FdoDevice = PdoExtension->FdoDevice;
336     FdoExtension = FdoDevice->DeviceExtension;
337     IoStack = IoGetCurrentIrpStackLocation(Irp);
338 
339     Status = Irp->IoStatus.Status;
340 
341     switch (IoStack->MinorFunction)
342     {
343       case IRP_MN_WAIT_WAKE:
344           DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE\n");
345 
346           if (!(FdoExtension->Flags & USBPORT_FLAG_HC_STARTED))
347           {
348               /* The device does not support wake-up */
349               Status = STATUS_NOT_SUPPORTED;
350               break;
351           }
352 
353           KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql);
354 
355           IoSetCancelRoutine(Irp, USBPORT_CancelPendingWakeIrp);
356 
357           /* Check if the IRP has been cancelled */
358           if (Irp->Cancel)
359           {
360               if (IoSetCancelRoutine(Irp, NULL))
361               {
362                   /* IRP has been cancelled, release cancel spinlock */
363                   KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
364 
365                   DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_CANCELLED\n");
366 
367                   /* IRP is cancelled */
368                   Status = STATUS_CANCELLED;
369                   break;
370               }
371           }
372 
373           if (!PdoExtension->WakeIrp)
374           {
375               /* The driver received the IRP
376                  and is waiting for the device to signal wake-up. */
377 
378               DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - No WakeIrp\n");
379 
380               IoMarkIrpPending(Irp);
381               PdoExtension->WakeIrp = Irp;
382 
383               KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
384               return STATUS_PENDING;
385           }
386           else
387           {
388               /* An IRP_MN_WAIT_WAKE request is already pending and must be
389                  completed or canceled before another IRP_MN_WAIT_WAKE request
390                  can be issued. */
391 
392               if (IoSetCancelRoutine(Irp, NULL))
393               {
394                   DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_DEVICE_BUSY\n");
395 
396                   KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
397                   PoStartNextPowerIrp(Irp);
398                   Status = STATUS_DEVICE_BUSY;
399                   break;
400               }
401               else
402               {
403                   ASSERT(FALSE);
404                   KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql);
405                   return Status;
406               }
407           }
408 
409       case IRP_MN_POWER_SEQUENCE:
410           DPRINT("USBPORT_PdoPower: IRP_MN_POWER_SEQUENCE\n");
411           PoStartNextPowerIrp(Irp);
412           break;
413 
414       case IRP_MN_SET_POWER:
415           DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER\n");
416 
417           if (IoStack->Parameters.Power.Type == DevicePowerState)
418           {
419               DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER/DevicePowerState\n");
420               Status = USBPORT_PdoDevicePowerState(PdoDevice, Irp);
421               PoStartNextPowerIrp(Irp);
422               break;
423           }
424 
425           DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER/SystemPowerState \n");
426 
427           if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking)
428           {
429               FdoExtension->TimerFlags |= USBPORT_TMFLAG_WAKE;
430           }
431           else
432           {
433               FdoExtension->TimerFlags &= ~USBPORT_TMFLAG_WAKE;
434           }
435 
436           Status = STATUS_SUCCESS;
437 
438           PoStartNextPowerIrp(Irp);
439           break;
440 
441       case IRP_MN_QUERY_POWER:
442           DPRINT("USBPORT_PdoPower: IRP_MN_QUERY_POWER\n");
443           Status = STATUS_SUCCESS;
444           PoStartNextPowerIrp(Irp);
445           break;
446 
447       default:
448           DPRINT1("USBPORT_PdoPower: unknown IRP_MN_POWER!\n");
449           PoStartNextPowerIrp(Irp);
450           break;
451     }
452 
453     Irp->IoStatus.Status = Status;
454     Irp->IoStatus.Information = 0;
455     IoCompleteRequest(Irp, IO_NO_INCREMENT);
456 
457     return Status;
458 }
459 
460 NTSTATUS
461 NTAPI
462 USBPORT_HcWake(IN PDEVICE_OBJECT FdoDevice,
463                IN PIRP Irp)
464 {
465     DPRINT1("USBPORT_HcWake: UNIMPLEMENTED. FIXME. \n");
466     return STATUS_SUCCESS;
467 }
468 
469 NTSTATUS
470 NTAPI
471 USBPORT_DevicePowerState(IN PDEVICE_OBJECT FdoDevice,
472                          IN PIRP Irp)
473 {
474     DPRINT1("USBPORT_DevicePowerState: UNIMPLEMENTED. FIXME. \n");
475     return STATUS_SUCCESS;
476 }
477 
478 NTSTATUS
479 NTAPI
480 USBPORT_SystemPowerState(IN PDEVICE_OBJECT FdoDevice,
481                          IN PIRP Irp)
482 {
483     DPRINT1("USBPORT_SystemPowerState: UNIMPLEMENTED. FIXME. \n");
484     return STATUS_SUCCESS;
485 }
486 
487 NTSTATUS
488 NTAPI
489 USBPORT_FdoPower(IN PDEVICE_OBJECT FdoDevice,
490                  IN PIRP Irp)
491 {
492     PUSBPORT_DEVICE_EXTENSION FdoExtension;
493     PIO_STACK_LOCATION IoStack;
494     NTSTATUS Status;
495 
496     DPRINT("USBPORT_FdoPower: ... \n");
497 
498     FdoExtension = FdoDevice->DeviceExtension;
499     IoStack = IoGetCurrentIrpStackLocation(Irp);
500 
501     switch (IoStack->MinorFunction)
502     {
503       case IRP_MN_WAIT_WAKE:
504           DPRINT("USBPORT_FdoPower: IRP_MN_WAIT_WAKE\n");
505           Status = USBPORT_HcWake(FdoDevice, Irp);
506           return Status;
507 
508       case IRP_MN_POWER_SEQUENCE:
509           DPRINT("USBPORT_FdoPower: IRP_MN_POWER_SEQUENCE\n");
510           break;
511 
512       case IRP_MN_SET_POWER:
513           DPRINT("USBPORT_FdoPower: IRP_MN_SET_POWER\n");
514           if (IoStack->Parameters.Power.Type == DevicePowerState)
515           {
516               Status = USBPORT_DevicePowerState(FdoDevice, Irp);
517           }
518           else
519           {
520               Status = USBPORT_SystemPowerState(FdoDevice, Irp);
521           }
522 
523           if (Status != STATUS_PENDING)
524               break;
525 
526           return Status;
527 
528       case IRP_MN_QUERY_POWER:
529           DPRINT("USBPORT_FdoPower: IRP_MN_QUERY_POWER\n");
530           Irp->IoStatus.Status = STATUS_SUCCESS;
531           break;
532 
533       default:
534           DPRINT1("USBPORT_FdoPower: unknown IRP_MN_POWER!\n");
535           break;
536     }
537 
538     IoCopyCurrentIrpStackLocationToNext(Irp);
539     PoStartNextPowerIrp(Irp);
540     return PoCallDriver(FdoExtension->CommonExtension.LowerDevice, Irp);
541 }
542 
543 VOID
544 NTAPI
545 USBPORT_DoIdleNotificationCallback(IN PVOID Context)
546 {
547     PIO_STACK_LOCATION IoStack;
548     PDEVICE_OBJECT FdoDevice;
549     PUSBPORT_DEVICE_EXTENSION FdoExtension;
550     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
551     PIRP NextIrp;
552     LARGE_INTEGER CurrentTime = {{0, 0}};
553     PTIMER_WORK_QUEUE_ITEM IdleQueueItem;
554     PDEVICE_OBJECT PdoDevice;
555     PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo;
556     KIRQL OldIrql;
557 
558     DPRINT("USBPORT_DoIdleNotificationCallback \n");
559 
560     IdleQueueItem = Context;
561 
562     FdoDevice = IdleQueueItem->FdoDevice;
563     FdoExtension = FdoDevice->DeviceExtension;
564     PdoDevice = FdoExtension->RootHubPdo;
565     PdoExtension = PdoDevice->DeviceExtension;
566 
567     KeQuerySystemTime(&CurrentTime);
568 
569     if ((FdoExtension->IdleTime.QuadPart == 0) ||
570         (((CurrentTime.QuadPart - FdoExtension->IdleTime.QuadPart) / 10000) >= 500))
571     {
572         if (PdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0 &&
573             FdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0)
574         {
575             NextIrp = IoCsqRemoveNextIrp(&FdoExtension->IdleIoCsq, NULL);
576 
577             if (NextIrp)
578             {
579                 IoStack = IoGetCurrentIrpStackLocation(NextIrp);
580                 IdleCallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
581 
582                 if (IdleCallbackInfo && IdleCallbackInfo->IdleCallback)
583                 {
584                     IdleCallbackInfo->IdleCallback(IdleCallbackInfo->IdleContext);
585                 }
586 
587                 if (NextIrp->Cancel)
588                 {
589                     InterlockedDecrement(&FdoExtension->IdleLockCounter);
590 
591                     NextIrp->IoStatus.Status = STATUS_CANCELLED;
592                     NextIrp->IoStatus.Information = 0;
593                     IoCompleteRequest(NextIrp, IO_NO_INCREMENT);
594                 }
595                 else
596                 {
597                     IoCsqInsertIrp(&FdoExtension->IdleIoCsq, NextIrp, NULL);
598                 }
599             }
600         }
601     }
602 
603     KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql);
604     FdoExtension->TimerFlags &= ~USBPORT_TMFLAG_IDLE_QUEUEITEM_ON;
605     KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql);
606 
607     ExFreePoolWithTag(IdleQueueItem, USB_PORT_TAG);
608 }
609 
610 NTSTATUS
611 NTAPI
612 USBPORT_IdleNotification(IN PDEVICE_OBJECT PdoDevice,
613                          IN PIRP Irp)
614 {
615     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
616     PDEVICE_OBJECT FdoDevice;
617     PUSBPORT_DEVICE_EXTENSION FdoExtension;
618     LONG LockCounter;
619     NTSTATUS Status = STATUS_PENDING;
620 
621     DPRINT("USBPORT_IdleNotification: Irp - %p\n", Irp);
622 
623     PdoExtension = PdoDevice->DeviceExtension;
624     FdoDevice = PdoExtension->FdoDevice;
625     FdoExtension = FdoDevice->DeviceExtension;
626 
627     LockCounter = InterlockedIncrement(&FdoExtension->IdleLockCounter);
628 
629     if (LockCounter != 0)
630     {
631         if (Status != STATUS_PENDING)
632         {
633             InterlockedDecrement(&FdoExtension->IdleLockCounter);
634 
635             Irp->IoStatus.Status = Status;
636             Irp->IoStatus.Information = 0;
637             IoCompleteRequest(Irp, IO_NO_INCREMENT);
638 
639             return Status;
640         }
641 
642         Status = STATUS_DEVICE_BUSY;
643     }
644 
645     if (Status != STATUS_PENDING)
646     {
647         InterlockedDecrement(&FdoExtension->IdleLockCounter);
648 
649         Irp->IoStatus.Status = Status;
650         Irp->IoStatus.Information = 0;
651         IoCompleteRequest(Irp, IO_NO_INCREMENT);
652 
653         return Status;
654     }
655 
656     Irp->IoStatus.Status = STATUS_PENDING;
657     IoMarkIrpPending(Irp);
658 
659     KeQuerySystemTime(&FdoExtension->IdleTime);
660 
661     IoCsqInsertIrp(&FdoExtension->IdleIoCsq, Irp, 0);
662 
663     return Status;
664 }
665 
666 VOID
667 NTAPI
668 USBPORT_AdjustDeviceCapabilities(IN PDEVICE_OBJECT FdoDevice,
669                                  IN PDEVICE_OBJECT PdoDevice)
670 {
671     PUSBPORT_DEVICE_EXTENSION FdoExtension;
672     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
673     PDEVICE_CAPABILITIES Capabilities;
674 
675     DPRINT("USBPORT_AdjustDeviceCapabilities: ... \n");
676 
677     FdoExtension = FdoDevice->DeviceExtension;
678     PdoExtension = PdoDevice->DeviceExtension;
679     Capabilities = &PdoExtension->Capabilities;
680 
681     RtlCopyMemory(Capabilities,
682                   &FdoExtension->Capabilities,
683                   sizeof(DEVICE_CAPABILITIES));
684 
685     Capabilities->DeviceD1 = FALSE;
686     Capabilities->DeviceD2 = TRUE;
687 
688     Capabilities->Removable = FALSE;
689     Capabilities->UniqueID = FALSE;
690 
691     Capabilities->WakeFromD0 = TRUE;
692     Capabilities->WakeFromD1 = FALSE;
693     Capabilities->WakeFromD2 = TRUE;
694     Capabilities->WakeFromD3 = FALSE;
695 
696     Capabilities->Address = 0;
697     Capabilities->UINumber = 0;
698 
699     if (Capabilities->SystemWake == PowerSystemUnspecified)
700         Capabilities->SystemWake = PowerSystemWorking;
701 
702     Capabilities->DeviceWake = PowerDeviceD2;
703 
704     Capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
705     Capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
706     Capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
707     Capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
708 }
709