VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/Device/vboxpwr.cpp@ 36486

Last change on this file since 36486 was 31896, checked in by vboxsync, 15 years ago

export the VBoxUSB host driver to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.0 KB
Line 
1/*++
2
3Copyright (c) 2000 Microsoft Corporation
4
5Module Name:
6
7 vboxpwr.c
8
9Abstract:
10
11 The power management related processing.
12
13 The Power Manager uses IRPs to direct drivers to change system
14 and device power levels, to respond to system wake-up events,
15 and to query drivers about their devices. All power IRPs have
16 the major function code IRP_MJ_POWER.
17
18 Most function and filter drivers perform some processing for
19 each power IRP, then pass the IRP down to the next lower driver
20 without completing it. Eventually the IRP reaches the bus driver,
21 which physically changes the power state of the device and completes
22 the IRP.
23
24 When the IRP has been completed, the I/O Manager calls any
25 IoCompletion routines set by drivers as the IRP traveled
26 down the device stack. Whether a driver needs to set a completion
27 routine depends upon the type of IRP and the driver's individual
28 requirements.
29
30 This code is not USB specific. It is essential for every WDM driver
31 to handle power irps.
32
33Environment:
34
35 Kernel mode
36
37Notes:
38
39 Copyright (c) 2000 Microsoft Corporation.
40 All Rights Reserved.
41
42--*/
43
44#include "vboxusb.h"
45#include "vboxpwr.h"
46#include "vboxpnp.h"
47#include "vboxdev.h"
48#include <iprt/assert.h>
49
50NTSTATUS
51VBoxUSB_DispatchPower(
52 IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp
54 )
55/*++
56
57Routine Description:
58
59 The power dispatch routine.
60
61Arguments:
62
63 DeviceObject - pointer to a device object.
64
65 Irp - pointer to an I/O Request Packet.
66
67Return Value:
68
69 NT status code
70
71--*/
72{
73 NTSTATUS ntStatus;
74 PIO_STACK_LOCATION irpStack;
75 PDEVICE_EXTENSION deviceExtension;
76
77 //
78 // initialize the variables
79 //
80
81 irpStack = IoGetCurrentIrpStackLocation(Irp);
82 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
83
84 //
85 // We don't queue power Irps, we'll only check if the
86 // device was removed, otherwise we'll take appropriate
87 // action and send it to the next lower driver. In general
88 // drivers should not cause long delays while handling power
89 // IRPs. If a driver cannot handle a power IRP in a brief time,
90 // it should return STATUS_PENDING and queue all incoming
91 // IRPs until the IRP completes.
92 //
93
94 if(Removed == deviceExtension->DeviceState) {
95
96 //
97 // Even if a driver fails the IRP, it must nevertheless call
98 // PoStartNextPowerIrp to inform the Power Manager that it
99 // is ready to handle another power IRP.
100 //
101
102 PoStartNextPowerIrp(Irp);
103
104 Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
105 Irp->IoStatus.Information = 0;
106
107 IoCompleteRequest(Irp, IO_NO_INCREMENT);
108
109 return ntStatus;
110 }
111
112 if(NotStarted == deviceExtension->DeviceState) {
113
114 //
115 // if the device is not started yet, pass it down
116 //
117
118 PoStartNextPowerIrp(Irp);
119
120 IoSkipCurrentIrpStackLocation(Irp);
121
122 return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
123 }
124
125 dprintf(("VBoxUSB_DispatchPower::"));
126 VBoxUSB_IoIncrement(deviceExtension);
127
128 switch(irpStack->MinorFunction) {
129
130 case IRP_MN_SET_POWER:
131
132 //
133 // The Power Manager sends this IRP for one of the
134 // following reasons:
135 // 1) To notify drivers of a change to the system power state.
136 // 2) To change the power state of a device for which
137 // the Power Manager is performing idle detection.
138 // A driver sends IRP_MN_SET_POWER to change the power
139 // state of its device if it's a power policy owner for the
140 // device.
141 //
142
143 IoMarkIrpPending(Irp);
144
145 switch(irpStack->Parameters.Power.Type) {
146
147 case SystemPowerState:
148
149 HandleSystemSetPower(DeviceObject, Irp);
150
151 ntStatus = STATUS_PENDING;
152
153 break;
154
155 case DevicePowerState:
156
157 HandleDeviceSetPower(DeviceObject, Irp);
158
159 ntStatus = STATUS_PENDING;
160
161 break;
162 }
163
164 break;
165
166 case IRP_MN_QUERY_POWER:
167
168 //
169 // The Power Manager sends a power IRP with the minor
170 // IRP code IRP_MN_QUERY_POWER to determine whether it
171 // can safely change to the specified system power state
172 // (S1-S5) and to allow drivers to prepare for such a change.
173 // If a driver can put its device in the requested state,
174 // it sets status to STATUS_SUCCESS and passes the IRP down.
175 //
176
177 IoMarkIrpPending(Irp);
178
179 switch(irpStack->Parameters.Power.Type) {
180
181 case SystemPowerState:
182
183 HandleSystemQueryPower(DeviceObject, Irp);
184
185 ntStatus = STATUS_PENDING;
186
187 break;
188
189 case DevicePowerState:
190
191 HandleDeviceQueryPower(DeviceObject, Irp);
192
193 ntStatus = STATUS_PENDING;
194
195 break;
196 }
197
198 break;
199
200 case IRP_MN_WAIT_WAKE:
201
202 //
203 // The minor power IRP code IRP_MN_WAIT_WAKE provides
204 // for waking a device or waking the system. Drivers
205 // of devices that can wake themselves or the system
206 // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
207 // only to devices that always wake the system, such as
208 // the power-on switch.
209 //
210
211 IoMarkIrpPending(Irp);
212
213 IoCopyCurrentIrpStackLocationToNext(Irp);
214
215 IoSetCompletionRoutine(
216 Irp,
217 (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
218 deviceExtension,
219 TRUE,
220 TRUE,
221 TRUE);
222
223 PoStartNextPowerIrp(Irp);
224
225 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
226
227 if(!NT_SUCCESS(ntStatus)) {
228
229 dprintf(("Lower drivers failed the wait-wake Irp\n"));
230 }
231
232 ntStatus = STATUS_PENDING;
233
234 //
235 // push back the count HERE and NOT in completion routine
236 // a pending Wait Wake Irp should not impede stopping the device
237 //
238
239 dprintf(("IRP_MN_WAIT_WAKE::"));
240 VBoxUSB_IoDecrement(deviceExtension);
241
242 break;
243
244 case IRP_MN_POWER_SEQUENCE:
245
246 //
247 // A driver sends this IRP as an optimization to determine
248 // whether its device actually entered a specific power state.
249 // This IRP is optional. Power Manager cannot send this IRP.
250 //
251
252 default:
253
254 PoStartNextPowerIrp(Irp);
255
256 IoSkipCurrentIrpStackLocation(Irp);
257
258 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
259
260 if(!NT_SUCCESS(ntStatus)) {
261
262 dprintf(("Lower drivers failed default power Irp\n"));
263 }
264
265 dprintf(("VBoxUSB_DispatchPower::"));
266 VBoxUSB_IoDecrement(deviceExtension);
267
268 break;
269 }
270
271 return ntStatus;
272}
273
274NTSTATUS
275HandleSystemQueryPower(
276 IN PDEVICE_OBJECT DeviceObject,
277 IN PIRP Irp
278 )
279/*++
280
281Routine Description:
282
283 This routine handles the irp with minor function of type IRP_MN_QUERY_POWER
284 for the system power states.
285
286Arguments:
287
288 DeviceObject - pointer to device object
289 Irp - I/O request packet sent by the power manager.
290
291Return Value:
292
293 NT status value
294
295--*/
296{
297 NTSTATUS ntStatus;
298 PDEVICE_EXTENSION deviceExtension;
299 SYSTEM_POWER_STATE systemState;
300 PIO_STACK_LOCATION irpStack;
301
302 dprintf(("HandleSystemQueryPower - begins\n"));
303
304 //
305 // initialize variables
306 //
307
308 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
309 irpStack = IoGetCurrentIrpStackLocation(Irp);
310 systemState = irpStack->Parameters.Power.State.SystemState;
311
312 dprintf(("Query for system power state S%X\n"
313 "Current system power state S%X\n",
314 systemState - 1,
315 deviceExtension->SysPower - 1));
316
317 //
318 // if querying for a lower S-state, issue a wait-wake
319 //
320
321 if((systemState > deviceExtension->SysPower) &&
322 (deviceExtension->WaitWakeEnable)) {
323
324 IssueWaitWake(deviceExtension);
325 }
326
327 IoCopyCurrentIrpStackLocationToNext(Irp);
328
329 IoSetCompletionRoutine(
330 Irp,
331 (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
332 deviceExtension,
333 TRUE,
334 TRUE,
335 TRUE);
336
337 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
338
339 dprintf(("HandleSystemQueryPower - ends\n"));
340
341 return STATUS_PENDING;
342}
343
344NTSTATUS
345HandleSystemSetPower(
346 IN PDEVICE_OBJECT DeviceObject,
347 IN PIRP Irp
348 )
349/*++
350
351Routine Description:
352
353 This routine services irps of minor type IRP_MN_SET_POWER
354 for the system power state
355
356Arguments:
357
358 DeviceObject - pointer to device object
359 Irp - I/O request packet sent by the power manager
360
361Return Value:
362
363 NT status value:
364
365--*/
366{
367 NTSTATUS ntStatus;
368 PDEVICE_EXTENSION deviceExtension;
369 SYSTEM_POWER_STATE systemState;
370 PIO_STACK_LOCATION irpStack;
371
372 dprintf(("HandleSystemSetPower - begins\n"));
373
374 //
375 // initialize variables
376 //
377
378 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
379 irpStack = IoGetCurrentIrpStackLocation(Irp);
380 systemState = irpStack->Parameters.Power.State.SystemState;
381
382 dprintf(("Set request for system power state S%X\n"
383 "Current system power state S%X\n",
384 systemState - 1,
385 deviceExtension->SysPower - 1));
386
387 IoCopyCurrentIrpStackLocationToNext(Irp);
388
389 IoSetCompletionRoutine(
390 Irp,
391 (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
392 deviceExtension,
393 TRUE,
394 TRUE,
395 TRUE);
396
397 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
398
399 dprintf(("HandleSystemSetPower - ends\n"));
400
401 return STATUS_PENDING;
402}
403
404NTSTATUS
405HandleDeviceQueryPower(
406 PDEVICE_OBJECT DeviceObject,
407 PIRP Irp
408 )
409/*++
410
411Routine Description:
412
413 This routine services irps of minor type IRP_MN_QUERY_POWER
414 for the device power state
415
416Arguments:
417
418 DeviceObject - pointer to device object
419 Irp - I/O request packet sent by the power manager
420
421Return Value:
422
423 NT status value
424
425--*/
426{
427 NTSTATUS ntStatus;
428 PDEVICE_EXTENSION deviceExtension;
429 PIO_STACK_LOCATION irpStack;
430 DEVICE_POWER_STATE deviceState;
431
432 dprintf(("HandleDeviceQueryPower - begins\n"));
433
434 //
435 // initialize variables
436 //
437
438 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
439 irpStack = IoGetCurrentIrpStackLocation(Irp);
440 deviceState = irpStack->Parameters.Power.State.DeviceState;
441
442 dprintf(("Query for device power state D%X\n"
443 "Current device power state D%X\n",
444 deviceState - 1,
445 deviceExtension->DevPower - 1));
446
447 if(deviceState < deviceExtension->DevPower) {
448
449 ntStatus = STATUS_SUCCESS;
450 }
451 else {
452
453 ntStatus = HoldIoRequests(DeviceObject, Irp);
454
455 if(STATUS_PENDING == ntStatus) {
456
457 return ntStatus;
458 }
459 }
460
461 //
462 // on error complete the Irp.
463 // on success pass it to the lower layers
464 //
465
466 PoStartNextPowerIrp(Irp);
467
468 Irp->IoStatus.Status = ntStatus;
469 Irp->IoStatus.Information = 0;
470
471 if(!NT_SUCCESS(ntStatus)) {
472
473 IoCompleteRequest(Irp, IO_NO_INCREMENT);
474 }
475 else {
476
477 IoSkipCurrentIrpStackLocation(Irp);
478
479 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
480 }
481
482 dprintf(("HandleDeviceQueryPower::"));
483 VBoxUSB_IoDecrement(deviceExtension);
484
485 dprintf(("HandleDeviceQueryPower - ends\n"));
486
487 return ntStatus;
488}
489
490
491NTSTATUS
492SysPoCompletionRoutine(
493 IN PDEVICE_OBJECT DeviceObject,
494 IN PIRP Irp,
495 IN PDEVICE_EXTENSION DeviceExtension
496 )
497/*++
498
499Routine Description:
500
501 This is the completion routine for the system power irps of minor
502 function types IRP_MN_QUERY_POWER and IRP_MN_SET_POWER.
503 This completion routine sends the corresponding device power irp and
504 returns STATUS_MORE_PROCESSING_REQUIRED. The system irp is passed as a
505 context to the device power irp completion routine and is completed in
506 the device power irp completion routine.
507
508Arguments:
509
510 DeviceObject - pointer to device object
511 Irp - I/O request packet
512 DeviceExtension - pointer to device extension
513
514Return Value:
515
516 NT status value
517
518--*/
519{
520 NTSTATUS ntStatus;
521 PIO_STACK_LOCATION irpStack;
522
523 //
524 // initialize variables
525 //
526 ntStatus = Irp->IoStatus.Status;
527 irpStack = IoGetCurrentIrpStackLocation(Irp);
528
529
530 dprintf(("SysPoCompletionRoutine - begins\n"));
531
532 //
533 // lower drivers failed this Irp
534 //
535
536 if(!NT_SUCCESS(ntStatus)) {
537
538 PoStartNextPowerIrp(Irp);
539
540 dprintf(("SysPoCompletionRoutine::"));
541 VBoxUSB_IoDecrement(DeviceExtension);
542
543 return STATUS_SUCCESS;
544 }
545
546 //
547 // ..otherwise update the cached system power state (IRP_MN_SET_POWER)
548 //
549
550 if(irpStack->MinorFunction == IRP_MN_SET_POWER) {
551
552 DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
553 }
554
555 //
556 // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
557 //
558
559 SendDeviceIrp(DeviceObject, Irp);
560
561 dprintf(("SysPoCompletionRoutine - ends\n"));
562
563 return STATUS_MORE_PROCESSING_REQUIRED;
564}
565
566VOID
567SendDeviceIrp(
568 IN PDEVICE_OBJECT DeviceObject,
569 IN PIRP SIrp
570 )
571/*++
572
573Routine Description:
574
575 This routine is invoked from the completion routine of the system power
576 irp. This routine will PoRequest a device power irp. The system irp is
577 passed as a context to the device power irp.
578
579Arguments:
580
581 DeviceObject - pointer to device object
582 SIrp - system power irp.
583
584Return Value:
585
586 None
587
588--*/
589{
590 NTSTATUS ntStatus;
591 POWER_STATE powState;
592 PDEVICE_EXTENSION deviceExtension;
593 PIO_STACK_LOCATION irpStack;
594 SYSTEM_POWER_STATE systemState;
595 DEVICE_POWER_STATE devState;
596 PPOWER_COMPLETION_CONTEXT powerContext;
597
598 //
599 // initialize variables
600 //
601
602 irpStack = IoGetCurrentIrpStackLocation(SIrp);
603 systemState = irpStack->Parameters.Power.State.SystemState;
604 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
605
606 dprintf(("SendDeviceIrp - begins\n"));
607
608 //
609 // Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
610 // we can choose deeper sleep states than our mapping but never choose
611 // lighter ones.
612 //
613
614 devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
615 powState.DeviceState = devState;
616
617 powerContext = (PPOWER_COMPLETION_CONTEXT)
618 ExAllocatePool(NonPagedPool,
619 sizeof(POWER_COMPLETION_CONTEXT));
620
621 if(!powerContext) {
622
623 dprintf(("Failed to alloc memory for powerContext\n"));
624
625 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
626 }
627 else {
628
629 powerContext->DeviceObject = DeviceObject;
630 powerContext->SIrp = SIrp;
631
632 //
633 // in win2k PoRequestPowerIrp can take fdo or pdo.
634 //
635
636 ntStatus = PoRequestPowerIrp(
637 deviceExtension->PhysicalDeviceObject,
638 irpStack->MinorFunction,
639 powState,
640 (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
641 powerContext,
642 NULL);
643 }
644
645 if(!NT_SUCCESS(ntStatus)) {
646
647 if(powerContext) {
648
649 ExFreePool(powerContext);
650 }
651
652 PoStartNextPowerIrp(SIrp);
653
654 SIrp->IoStatus.Status = ntStatus;
655 SIrp->IoStatus.Information = 0;
656
657 IoCompleteRequest(SIrp, IO_NO_INCREMENT);
658
659 dprintf(("SendDeviceIrp::"));
660 VBoxUSB_IoDecrement(deviceExtension);
661
662 }
663
664 dprintf(("SendDeviceIrp - ends\n"));
665}
666
667
668VOID
669DevPoCompletionRoutine(
670 IN PDEVICE_OBJECT DeviceObject,
671 IN UCHAR MinorFunction,
672 IN POWER_STATE PowerState,
673 IN PVOID Context,
674 IN PIO_STATUS_BLOCK IoStatus
675 )
676/*++
677
678Routine Description:
679
680 This is the PoRequest - completion routine for the device power irp.
681 This routine is responsible for completing the system power irp,
682 received as a context.
683
684Arguments:
685
686 DeviceObject - pointer to device object
687 MinorFunction - minor function of the irp.
688 PowerState - power state of the irp.
689 Context - context passed to the completion routine.
690 IoStatus - status of the device power irp.
691
692Return Value:
693
694 None
695
696--*/
697{
698 PIRP sIrp;
699 PDEVICE_EXTENSION deviceExtension;
700 PPOWER_COMPLETION_CONTEXT powerContext;
701
702 //
703 // initialize variables
704 //
705
706 powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
707 sIrp = powerContext->SIrp;
708 deviceExtension = (PDEVICE_EXTENSION)powerContext->DeviceObject->DeviceExtension;
709
710 dprintf(("DevPoCompletionRoutine - begins\n"));
711
712 //
713 // copy the D-Irp status into S-Irp
714 //
715
716 sIrp->IoStatus.Status = IoStatus->Status;
717
718 //
719 // complete the system Irp
720 //
721
722 PoStartNextPowerIrp(sIrp);
723
724 sIrp->IoStatus.Information = 0;
725
726 IoCompleteRequest(sIrp, IO_NO_INCREMENT);
727
728 //
729 // cleanup
730 //
731
732 dprintf(("DevPoCompletionRoutine::"));
733 VBoxUSB_IoDecrement(deviceExtension);
734
735 ExFreePool(powerContext);
736
737 dprintf(("DevPoCompletionRoutine - ends\n"));
738
739}
740
741NTSTATUS
742HandleDeviceSetPower(
743 IN PDEVICE_OBJECT DeviceObject,
744 IN PIRP Irp
745 )
746/*++
747
748Routine Description:
749
750 This routine services irps of minor type IRP_MN_SET_POWER
751 for the device power state
752
753Arguments:
754
755 DeviceObject - pointer to device object
756 Irp - I/O request packet sent by the power manager
757
758Return Value:
759
760 NT status value
761
762--*/
763{
764 KIRQL oldIrql;
765 NTSTATUS ntStatus;
766 POWER_STATE newState;
767 PIO_STACK_LOCATION irpStack;
768 PDEVICE_EXTENSION deviceExtension;
769 DEVICE_POWER_STATE newDevState,
770 oldDevState;
771
772 dprintf(("HandleDeviceSetPower - begins\n"));
773
774 //
775 // initialize variables
776 //
777
778 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
779 irpStack = IoGetCurrentIrpStackLocation(Irp);
780 oldDevState = deviceExtension->DevPower;
781 newState = irpStack->Parameters.Power.State;
782 newDevState = newState.DeviceState;
783
784 dprintf(("Set request for device power state D%X\n"
785 "Current device power state D%X\n",
786 newDevState - 1,
787 deviceExtension->DevPower - 1));
788
789 if(newDevState < oldDevState) {
790
791 //
792 // adding power
793 //
794 dprintf(("Adding power to the device\n"));
795
796 //
797 // send the power IRP to the next driver in the stack
798 //
799 IoCopyCurrentIrpStackLocationToNext(Irp);
800
801 IoSetCompletionRoutine(
802 Irp,
803 (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
804 deviceExtension,
805 TRUE,
806 TRUE,
807 TRUE);
808
809 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
810
811 }
812 else {
813
814 //
815 // newDevState >= oldDevState
816 //
817 // hold I/O if transition from D0 -> DX (X = 1, 2, 3)
818 // if transition from D1 or D2 to deeper sleep states,
819 // I/O queue is already on hold.
820 //
821
822 if(PowerDeviceD0 == oldDevState && newDevState > oldDevState) {
823
824 //
825 // D0 -> DX transition
826 //
827
828 dprintf(("Removing power from the device\n"));
829
830 ntStatus = HoldIoRequests(DeviceObject, Irp);
831
832 if(!NT_SUCCESS(ntStatus)) {
833
834 PoStartNextPowerIrp(Irp);
835
836 Irp->IoStatus.Status = ntStatus;
837 Irp->IoStatus.Information = 0;
838
839 IoCompleteRequest(Irp, IO_NO_INCREMENT);
840
841 dprintf(("HandleDeviceSetPower::"));
842 VBoxUSB_IoDecrement(deviceExtension);
843
844 return ntStatus;
845 }
846 else {
847
848 goto HandleDeviceSetPower_Exit;
849 }
850
851 }
852 else if(PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState) {
853
854 //
855 // D0 -> D0
856 // unblock the queue which may have been blocked processing
857 // query irp
858 //
859
860 dprintf(("A SetD0 request\n"));
861
862 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
863
864 deviceExtension->QueueState = AllowRequests;
865
866 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
867
868 ProcessQueuedRequests(deviceExtension);
869 }
870
871 IoCopyCurrentIrpStackLocationToNext(Irp);
872
873 IoSetCompletionRoutine(
874 Irp,
875 (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
876 deviceExtension,
877 TRUE,
878 TRUE,
879 TRUE);
880
881 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
882
883 if(!NT_SUCCESS(ntStatus)) {
884
885 dprintf(("Lower drivers failed a power Irp\n"));
886 }
887
888 }
889
890HandleDeviceSetPower_Exit:
891
892 dprintf(("HandleDeviceSetPower - ends\n"));
893
894 return STATUS_PENDING;
895}
896
897NTSTATUS
898FinishDevPoUpIrp(
899 IN PDEVICE_OBJECT DeviceObject,
900 IN PIRP Irp,
901 IN PDEVICE_EXTENSION DeviceExtension
902 )
903/*++
904
905Routine Description:
906
907 completion routine for the device power UP irp with minor function
908 IRP_MN_SET_POWER.
909
910Arguments:
911
912 DeviceObject - pointer to device object
913 Irp - I/O request packet
914 DeviceExtension - pointer to device extension
915
916Return Value:
917
918 NT status value
919
920--*/
921{
922 NTSTATUS ntStatus;
923
924 //
925 // initialize variables
926 //
927
928 ntStatus = Irp->IoStatus.Status;
929
930 dprintf(("FinishDevPoUpIrp - begins\n"));
931
932 if(Irp->PendingReturned) {
933
934 IoMarkIrpPending(Irp);
935 }
936
937 if(!NT_SUCCESS(ntStatus)) {
938
939 PoStartNextPowerIrp(Irp);
940
941 dprintf(("FinishDevPoUpIrp::"));
942 VBoxUSB_IoDecrement(DeviceExtension);
943
944 return STATUS_SUCCESS;
945 }
946
947 SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
948
949 dprintf(("FinishDevPoUpIrp - ends\n"));
950
951 return STATUS_MORE_PROCESSING_REQUIRED;
952}
953
954NTSTATUS
955SetDeviceFunctional(
956 IN PDEVICE_OBJECT DeviceObject,
957 IN PIRP Irp,
958 IN PDEVICE_EXTENSION DeviceExtension
959 )
960/*++
961
962Routine Description:
963
964 This routine processes queue of pending irps.
965
966Arguments:
967
968 DeviceObject - pointer to device object
969 Irp - I/O request packet
970 DeviceExtension - pointer to device extension
971
972Return Value:
973
974 NT status value
975
976--*/
977{
978 KIRQL oldIrql;
979 NTSTATUS ntStatus;
980 POWER_STATE newState;
981 PIO_STACK_LOCATION irpStack;
982 DEVICE_POWER_STATE newDevState,
983 oldDevState;
984
985 //
986 // initialize variables
987 //
988
989 ntStatus = Irp->IoStatus.Status;
990 irpStack = IoGetCurrentIrpStackLocation(Irp);
991 newState = irpStack->Parameters.Power.State;
992 newDevState = newState.DeviceState;
993 oldDevState = DeviceExtension->DevPower;
994
995 dprintf(("SetDeviceFunctional - begins\n"));
996
997 //
998 // update the cached state
999 //
1000 DeviceExtension->DevPower = newDevState;
1001
1002 //
1003 // restore appropriate amount of state to our h/w
1004 // this driver does not implement partial context
1005 // save/restore.
1006 //
1007
1008 PoSetPowerState(DeviceObject, DevicePowerState, newState);
1009
1010 if(PowerDeviceD0 == newDevState) {
1011
1012 //
1013 // empty existing queue of all pending irps.
1014 //
1015
1016 KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
1017
1018 DeviceExtension->QueueState = AllowRequests;
1019
1020 KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
1021
1022 ProcessQueuedRequests(DeviceExtension);
1023 }
1024
1025 PoStartNextPowerIrp(Irp);
1026
1027 Irp->IoStatus.Status = STATUS_SUCCESS;
1028 Irp->IoStatus.Information = 0;
1029
1030 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1031
1032 dprintf(("SetDeviceFunctional::"));
1033 VBoxUSB_IoDecrement(DeviceExtension);
1034
1035 dprintf(("SetDeviceFunctional - ends\n"));
1036
1037 return STATUS_SUCCESS;
1038}
1039
1040NTSTATUS
1041FinishDevPoDnIrp(
1042 IN PDEVICE_OBJECT DeviceObject,
1043 IN PIRP Irp,
1044 IN PDEVICE_EXTENSION DeviceExtension
1045 )
1046/*++
1047
1048Routine Description:
1049
1050 This routine is the completion routine for device power DOWN irp.
1051
1052Arguments:
1053
1054 DeviceObject - pointer to device object
1055 Irp - I/O request packet
1056 DeviceExtension - pointer to device extension
1057
1058Return Value:
1059
1060 NT status value
1061
1062--*/
1063{
1064 NTSTATUS ntStatus;
1065 POWER_STATE newState;
1066 PIO_STACK_LOCATION irpStack;
1067
1068 //
1069 // initialize variables
1070 //
1071 ntStatus = Irp->IoStatus.Status;
1072 irpStack = IoGetCurrentIrpStackLocation(Irp);
1073 newState = irpStack->Parameters.Power.State;
1074
1075 dprintf(("FinishDevPoDnIrp - begins\n"));
1076
1077 if(NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) {
1078
1079 //
1080 // update the cache;
1081 //
1082
1083 dprintf(("updating cache..\n"));
1084
1085 DeviceExtension->DevPower = newState.DeviceState;
1086
1087 PoSetPowerState(DeviceObject, DevicePowerState, newState);
1088 }
1089
1090 PoStartNextPowerIrp(Irp);
1091
1092 dprintf(("FinishDevPoDnIrp::"));
1093 VBoxUSB_IoDecrement(DeviceExtension);
1094
1095 dprintf(("FinishDevPoDnIrp - ends\n"));
1096
1097 return STATUS_SUCCESS;
1098}
1099
1100NTSTATUS
1101HoldIoRequests(
1102 IN PDEVICE_OBJECT DeviceObject,
1103 IN PIRP Irp
1104 )
1105/*++
1106
1107Routine Description:
1108
1109 This routine is called on query or set power DOWN irp for the device.
1110 This routine queues a workitem.
1111
1112Arguments:
1113
1114 DeviceObject - pointer to device object
1115 Irp - I/O request packet
1116
1117Return Value:
1118
1119 NT status value
1120
1121--*/
1122{
1123 NTSTATUS ntStatus;
1124 PIO_WORKITEM item;
1125 PDEVICE_EXTENSION deviceExtension;
1126 PWORKER_THREAD_CONTEXT context;
1127
1128 //
1129 // initialize variables
1130 //
1131 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1132
1133 dprintf(("HoldIoRequests - begins\n"));
1134
1135 deviceExtension->QueueState = HoldRequests;
1136
1137 context = (PWORKER_THREAD_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
1138
1139 if(context) {
1140
1141 item = IoAllocateWorkItem(DeviceObject);
1142
1143 context->Irp = Irp;
1144 context->DeviceObject = DeviceObject;
1145 context->WorkItem = item;
1146
1147 if(item) {
1148
1149 IoMarkIrpPending(Irp);
1150
1151 IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine,
1152 DelayedWorkQueue, context);
1153
1154 ntStatus = STATUS_PENDING;
1155 }
1156 else {
1157
1158 dprintf(("Failed to allocate memory for workitem\n"));
1159 ExFreePool(context);
1160 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1161 }
1162 }
1163 else {
1164
1165 dprintf(("Failed to alloc memory for worker thread context\n"));
1166 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1167 }
1168
1169 dprintf(("HoldIoRequests - ends\n"));
1170
1171 return ntStatus;
1172}
1173
1174VOID
1175HoldIoRequestsWorkerRoutine(
1176 IN PDEVICE_OBJECT DeviceObject,
1177 IN PVOID Context
1178 )
1179/*++
1180
1181Routine Description:
1182
1183 This routine waits for the I/O in progress to finish and then
1184 sends the device power irp (query/set) down the stack.
1185
1186Arguments:
1187
1188 DeviceObject - pointer to device object
1189 Context - context passed to the work-item.
1190
1191Return Value:
1192
1193 None
1194
1195--*/
1196{
1197 PIRP irp;
1198 NTSTATUS ntStatus;
1199 PDEVICE_EXTENSION deviceExtension;
1200 PWORKER_THREAD_CONTEXT context;
1201
1202 dprintf(("HoldIoRequestsWorkerRoutine - begins\n"));
1203
1204 //
1205 // initialize variables
1206 //
1207 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1208 context = (PWORKER_THREAD_CONTEXT) Context;
1209 irp = (PIRP) context->Irp;
1210
1211
1212 //
1213 // wait for I/O in progress to finish.
1214 // the stop event is signalled when the counter drops to 1.
1215 // invoke VBoxUSB_IoDecrement twice: once each for the S-Irp and D-Irp.
1216 //
1217 dprintf(("HoldIoRequestsWorkerRoutine::"));
1218 VBoxUSB_IoDecrement(deviceExtension);
1219 dprintf(("HoldIoRequestsWorkerRoutine::"));
1220 VBoxUSB_IoDecrement(deviceExtension);
1221
1222 KeWaitForSingleObject(&deviceExtension->StopEvent, Executive,
1223 KernelMode, FALSE, NULL);
1224
1225 //
1226 // Increment twice to restore the count
1227 //
1228 dprintf(("HoldIoRequestsWorkerRoutine::"));
1229 VBoxUSB_IoIncrement(deviceExtension);
1230 dprintf(("HoldIoRequestsWorkerRoutine::"));
1231 VBoxUSB_IoIncrement(deviceExtension);
1232
1233 //
1234 // now send the Irp down
1235 //
1236
1237 IoCopyCurrentIrpStackLocationToNext(irp);
1238
1239 IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
1240 deviceExtension, TRUE, TRUE, TRUE);
1241
1242 ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
1243
1244 if(!NT_SUCCESS(ntStatus)) {
1245
1246 dprintf(("Lower driver fail a power Irp\n"));
1247 }
1248
1249 IoFreeWorkItem(context->WorkItem);
1250 ExFreePool((PVOID)context);
1251
1252 dprintf(("HoldIoRequestsWorkerRoutine - ends\n"));
1253
1254}
1255
1256NTSTATUS
1257QueueRequest(
1258 IN OUT PDEVICE_EXTENSION DeviceExtension,
1259 IN PIRP Irp
1260 )
1261/*++
1262
1263Routine Description:
1264
1265 Queue the Irp in the device queue
1266
1267Arguments:
1268
1269 DeviceExtension - pointer to device extension
1270 Irp - I/O request packet.
1271
1272Return Value:
1273
1274 NT status value
1275
1276--*/
1277{
1278 KIRQL oldIrql;
1279 NTSTATUS ntStatus;
1280
1281 //
1282 // initialize variables
1283 //
1284 ntStatus = STATUS_PENDING;
1285
1286 dprintf(("QueueRequests - begins\n"));
1287
1288 ASSERT(HoldRequests == DeviceExtension->QueueState);
1289
1290 KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
1291
1292 InsertTailList(&DeviceExtension->NewRequestsQueue,
1293 &Irp->Tail.Overlay.ListEntry);
1294
1295 IoMarkIrpPending(Irp);
1296
1297 //
1298 // Set the cancel routine
1299 //
1300
1301 IoSetCancelRoutine(Irp, CancelQueued);
1302
1303 KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
1304
1305 dprintf(("QueueRequests - ends\n"));
1306
1307 return ntStatus;
1308}
1309
1310VOID
1311CancelQueued(
1312 IN PDEVICE_OBJECT DeviceObject,
1313 IN PIRP Irp
1314 )
1315/*++
1316
1317Routine Description:
1318
1319 This routine removes the irp from the queue and completes it with
1320 STATUS_CANCELLED
1321
1322Arguments:
1323
1324 DeviceObject - pointer to device object
1325 Irp - I/O request packet
1326
1327Return Value:
1328
1329 None.
1330
1331--*/
1332{
1333 PDEVICE_EXTENSION deviceExtension;
1334 KIRQL oldIrql;
1335
1336 //
1337 // initialize variables
1338 //
1339 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1340 oldIrql = Irp->CancelIrql;
1341
1342 dprintf(("CancelQueued - begins\n"));
1343
1344 //
1345 // Release the cancel spin lock
1346 //
1347
1348 IoReleaseCancelSpinLock(Irp->CancelIrql);
1349
1350 //
1351 // Acquire the queue lock
1352 //
1353
1354 KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
1355
1356 //
1357 // Remove the cancelled Irp from queue and release the lock
1358 //
1359 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1360
1361 KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
1362
1363 //
1364 // complete with STATUS_CANCELLED
1365 //
1366
1367 Irp->IoStatus.Status = STATUS_CANCELLED;
1368 Irp->IoStatus.Information = 0;
1369 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1370
1371 dprintf(("CancelQueued - ends\n"));
1372
1373 return;
1374}
1375
1376NTSTATUS
1377IssueWaitWake(
1378 IN PDEVICE_EXTENSION DeviceExtension
1379 )
1380/*++
1381
1382Routine Description:
1383
1384 This routine will PoRequest a WAIT WAKE irp for the device
1385
1386Arguments:
1387
1388 DeviceExtension - pointer to device extension
1389
1390Return Value:
1391
1392 NT status value.
1393
1394--*/
1395{
1396 POWER_STATE poState;
1397 NTSTATUS ntStatus;
1398
1399 dprintf(("IssueWaitWake - begins\n"));
1400
1401 if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1)) {
1402
1403 return STATUS_DEVICE_BUSY;
1404 }
1405
1406 InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
1407
1408 //
1409 // lowest state from which this Irp will wake the system
1410 //
1411
1412 poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
1413
1414 ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
1415 IRP_MN_WAIT_WAKE,
1416 poState,
1417 (PREQUEST_POWER_COMPLETE) WaitWakeCallback,
1418 DeviceExtension,
1419 &DeviceExtension->WaitWakeIrp);
1420
1421 if(!NT_SUCCESS(ntStatus)) {
1422
1423 InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
1424 }
1425
1426 dprintf(("IssueWaitWake - ends\n"));
1427
1428 return ntStatus;
1429}
1430
1431VOID
1432CancelWaitWake(
1433 IN PDEVICE_EXTENSION DeviceExtension
1434 )
1435/*++
1436
1437Routine Description:
1438
1439 This routine cancels the Wait Wake request.
1440
1441Arguments:
1442
1443 DeviceExtension - pointer to the device extension
1444
1445Return Value:
1446
1447 None.
1448
1449--*/
1450{
1451 PIRP Irp;
1452
1453 dprintf(("CancelWaitWake - begins\n"));
1454
1455 Irp = (PIRP) InterlockedExchangePointer((PVOID *)&DeviceExtension->WaitWakeIrp,
1456 NULL);
1457
1458 if(Irp) {
1459
1460 IoCancelIrp(Irp);
1461
1462 if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
1463
1464 PoStartNextPowerIrp(Irp);
1465
1466 Irp->IoStatus.Status = STATUS_CANCELLED;
1467 Irp->IoStatus.Information = 0;
1468
1469 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1470 }
1471 }
1472
1473 dprintf(("CancelWaitWake - ends\n"));
1474}
1475
1476NTSTATUS
1477WaitWakeCompletionRoutine(
1478 IN PDEVICE_OBJECT DeviceObject,
1479 IN PIRP Irp,
1480 IN PDEVICE_EXTENSION DeviceExtension
1481 )
1482/*++
1483
1484Routine Description:
1485
1486 This is the IoSet completion routine for the wait wake irp.
1487
1488Arguments:
1489
1490 DeviceObject - pointer to device object
1491 Irp - I/O request packet
1492 DeviceExtension - pointer to device extension
1493
1494Return Value:
1495
1496 NT status value
1497
1498--*/
1499{
1500 dprintf(("WaitWakeCompletionRoutine - begins\n"));
1501
1502 if(Irp->PendingReturned) {
1503
1504 IoMarkIrpPending(Irp);
1505 }
1506
1507 //
1508 // Nullify the WaitWakeIrp pointer-the Irp is released
1509 // as part of the completion process. If it's already NULL,
1510 // avoid race with the CancelWaitWake routine.
1511 //
1512
1513 if(InterlockedExchangePointer((PVOID *)&DeviceExtension->WaitWakeIrp, NULL)) {
1514
1515 PoStartNextPowerIrp(Irp);
1516
1517 return STATUS_SUCCESS;
1518 }
1519
1520 //
1521 // CancelWaitWake has run.
1522 // If FlagWWCancel != 0, complete the Irp.
1523 // If FlagWWCancel == 0, CancelWaitWake completes it.
1524 //
1525 if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
1526
1527 PoStartNextPowerIrp(Irp);
1528
1529 return STATUS_CANCELLED;
1530 }
1531
1532 dprintf(("WaitWakeCompletionRoutine - ends\n"));
1533
1534 return STATUS_MORE_PROCESSING_REQUIRED;
1535}
1536
1537VOID
1538WaitWakeCallback(
1539 IN PDEVICE_OBJECT DeviceObject,
1540 IN UCHAR MinorFunction,
1541 IN POWER_STATE PowerState,
1542 IN PVOID Context,
1543 IN PIO_STATUS_BLOCK IoStatus
1544 )
1545/*++
1546
1547Routine Description:
1548
1549 This is the PoRequest completion routine for the wait wake irp.
1550
1551Arguments:
1552
1553 DeviceObject - pointer to device object
1554 MinorFunction - irp minor function
1555 PowerState - power state of the irp.
1556 Context - context passed to the completion routine.
1557 IoStatus - status block.
1558
1559Return Value:
1560
1561 None
1562
1563--*/
1564{
1565 NTSTATUS ntStatus;
1566 POWER_STATE powerState;
1567 PDEVICE_EXTENSION deviceExtension;
1568
1569 dprintf(("WaitWakeCallback - begins\n"));
1570
1571 deviceExtension = (PDEVICE_EXTENSION) Context;
1572
1573 InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
1574
1575 if(!NT_SUCCESS(IoStatus->Status)) {
1576
1577 return;
1578 }
1579
1580 //
1581 // wake up the device
1582 //
1583
1584 if(deviceExtension->DevPower == PowerDeviceD0) {
1585
1586 dprintf(("device already powered up...\n"));
1587
1588 return;
1589 }
1590
1591 dprintf(("WaitWakeCallback::"));
1592 VBoxUSB_IoIncrement(deviceExtension);
1593
1594 powerState.DeviceState = PowerDeviceD0;
1595
1596 ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
1597 IRP_MN_SET_POWER,
1598 powerState,
1599 (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
1600 deviceExtension,
1601 NULL);
1602
1603 if(deviceExtension->WaitWakeEnable) {
1604
1605 IssueWaitWake(deviceExtension);
1606 }
1607
1608 dprintf(("WaitWakeCallback - ends\n"));
1609
1610 return;
1611}
1612
1613
1614PCHAR
1615PowerMinorFunctionString (
1616 IN UCHAR MinorFunction
1617 )
1618/*++
1619
1620Routine Description:
1621
1622Arguments:
1623
1624Return Value:
1625
1626--*/
1627{
1628 switch (MinorFunction) {
1629
1630 case IRP_MN_SET_POWER:
1631 return "IRP_MN_SET_POWER\n";
1632
1633 case IRP_MN_QUERY_POWER:
1634 return "IRP_MN_QUERY_POWER\n";
1635
1636 case IRP_MN_POWER_SEQUENCE:
1637 return "IRP_MN_POWER_SEQUENCE\n";
1638
1639 case IRP_MN_WAIT_WAKE:
1640 return "IRP_MN_WAIT_WAKE\n";
1641
1642 default:
1643 return "IRP_MN_?????\n";
1644 }
1645}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette