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