xref: /reactos/drivers/bluetooth/fbtusb/fbtpwr.c (revision c2c66aff)
1 // Copyright (c) 2004, Antony C. Roberts
2 
3 // Use of this file is subject to the terms
4 // described in the LICENSE.TXT file that
5 // accompanies this file.
6 //
7 // Your use of this file indicates your
8 // acceptance of the terms described in
9 // LICENSE.TXT.
10 //
11 // http://www.freebt.net
12 
13 #include "fbtusb.h"
14 #include "fbtpwr.h"
15 #include "fbtpnp.h"
16 #include "fbtdev.h"
17 #include "fbtrwr.h"
18 #include "fbtwmi.h"
19 
20 #include "fbtusr.h"
21 
22 // Handle power events
FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)23 NTSTATUS NTAPI FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
24 {
25     NTSTATUS           ntStatus = STATUS_SUCCESS;
26     PIO_STACK_LOCATION irpStack;
27     //PUNICODE_STRING    tagString;
28     PDEVICE_EXTENSION  deviceExtension;
29 
30     irpStack = IoGetCurrentIrpStackLocation(Irp);
31     deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
32 
33     // We don't queue power Irps, we'll only check if the
34     // device was removed, otherwise we'll take appropriate
35     // action and send it to the next lower driver. In general
36     // drivers should not cause long delays while handling power
37     // IRPs. If a driver cannot handle a power IRP in a brief time,
38     // it should return STATUS_PENDING and queue all incoming
39     // IRPs until the IRP completes.
40     if (Removed == deviceExtension->DeviceState)
41     {
42 
43         // Even if a driver fails the IRP, it must nevertheless call
44         // PoStartNextPowerIrp to inform the Power Manager that it
45         // is ready to handle another power IRP.
46         PoStartNextPowerIrp(Irp);
47         Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
48         Irp->IoStatus.Information = 0;
49         IoCompleteRequest(Irp, IO_NO_INCREMENT);
50 
51         return ntStatus;
52 
53     }
54 
55     if (NotStarted == deviceExtension->DeviceState)
56     {
57         // if the device is not started yet, pass it down
58         PoStartNextPowerIrp(Irp);
59         IoSkipCurrentIrpStackLocation(Irp);
60 
61         return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
62 
63     }
64 
65     FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
66     FreeBT_IoIncrement(deviceExtension);
67 
68     switch(irpStack->MinorFunction)
69     {
70     case IRP_MN_SET_POWER:
71         // The Power Manager sends this IRP for one of the
72         // following reasons:
73 
74         // 1) To notify drivers of a change to the system power state.
75         // 2) To change the power state of a device for which
76         //    the Power Manager is performing idle detection.
77 
78         // A driver sends IRP_MN_SET_POWER to change the power
79         // state of its device if it's a power policy owner for the
80         // device.
81         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_SET_POWER\n"));
82         IoMarkIrpPending(Irp);
83 
84         switch(irpStack->Parameters.Power.Type)
85         {
86         case SystemPowerState:
87             HandleSystemSetPower(DeviceObject, Irp);
88             ntStatus = STATUS_PENDING;
89             break;
90 
91         case DevicePowerState:
92             HandleDeviceSetPower(DeviceObject, Irp);
93             ntStatus = STATUS_PENDING;
94             break;
95 
96         }
97 
98         break;
99 
100     case IRP_MN_QUERY_POWER:
101         // The Power Manager sends a power IRP with the minor
102         // IRP code IRP_MN_QUERY_POWER to determine whether it
103         // can safely change to the specified system power state
104         // (S1-S5) and to allow drivers to prepare for such a change.
105         // If a driver can put its device in the requested state,
106         // it sets status to STATUS_SUCCESS and passes the IRP down.
107         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_QUERY_POWER\n"));
108         IoMarkIrpPending(Irp);
109 
110         switch(irpStack->Parameters.Power.Type)
111         {
112         case SystemPowerState:
113             HandleSystemQueryPower(DeviceObject, Irp);
114             ntStatus = STATUS_PENDING;
115             break;
116 
117         case DevicePowerState:
118             HandleDeviceQueryPower(DeviceObject, Irp);
119             ntStatus = STATUS_PENDING;
120             break;
121 
122         }
123 
124         break;
125 
126     case IRP_MN_WAIT_WAKE:
127         // The minor power IRP code IRP_MN_WAIT_WAKE provides
128         // for waking a device or waking the system. Drivers
129         // of devices that can wake themselves or the system
130         // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
131         // only to devices that always wake the system, such as
132         // the power-on switch.
133         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE\n"));
134         IoMarkIrpPending(Irp);
135         IoCopyCurrentIrpStackLocationToNext(Irp);
136         IoSetCompletionRoutine(
137                         Irp,
138                         (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
139                         deviceExtension,
140                         TRUE,
141                         TRUE,
142                         TRUE);
143 
144         PoStartNextPowerIrp(Irp);
145         ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
146         if(!NT_SUCCESS(ntStatus))
147         {
148             FreeBT_DbgPrint(1, ("FBTUSB: Lower drivers failed the wait-wake Irp\n"));
149 
150         }
151 
152         ntStatus = STATUS_PENDING;
153 
154         // push back the count HERE and NOT in completion routine
155         // a pending Wait Wake Irp should not impede stopping the device
156         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE::"));
157         FreeBT_IoDecrement(deviceExtension);
158         break;
159 
160     case IRP_MN_POWER_SEQUENCE:
161         // A driver sends this IRP as an optimization to determine
162         // whether its device actually entered a specific power state.
163         // This IRP is optional. Power Manager cannot send this IRP.
164         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_POWER_SEQUENCE\n"));
165 
166     default:
167         PoStartNextPowerIrp(Irp);
168         IoSkipCurrentIrpStackLocation(Irp);
169         ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
170         if(!NT_SUCCESS(ntStatus))
171         {
172             FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchPower: Lower drivers failed this Irp\n"));
173 
174         }
175 
176         FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
177         FreeBT_IoDecrement(deviceExtension);
178 
179         break;
180 
181     }
182 
183     return ntStatus;
184 
185 }
186 
HandleSystemQueryPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)187 NTSTATUS NTAPI HandleSystemQueryPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
188 {
189     NTSTATUS           ntStatus;
190     PDEVICE_EXTENSION  deviceExtension;
191     SYSTEM_POWER_STATE systemState;
192     PIO_STACK_LOCATION irpStack;
193 
194     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Entered\n"));
195 
196     // initialize variables
197     deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
198     irpStack = IoGetCurrentIrpStackLocation(Irp);
199     systemState = irpStack->Parameters.Power.State.SystemState;
200 
201     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Query for system power state S%X\n"
202                         "FBTUSB: HandleSystemQueryPower: Current system power state S%X\n",
203                          systemState - 1,
204                          deviceExtension->SysPower - 1));
205 
206     // Fail a query for a power state incompatible with waking up the system
207     if ((deviceExtension->WaitWakeEnable) && (systemState > deviceExtension->DeviceCapabilities.SystemWake))
208     {
209         FreeBT_DbgPrint(1, ("FBTUSB: HandleSystemQueryPower: Query for an incompatible system power state\n"));
210 
211         PoStartNextPowerIrp(Irp);
212         Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
213         Irp->IoStatus.Information = 0;
214         IoCompleteRequest(Irp, IO_NO_INCREMENT);
215 
216         FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower::"));
217         FreeBT_IoDecrement(deviceExtension);
218 
219         return ntStatus;
220 
221     }
222 
223     // if querying for a lower S-state, issue a wait-wake
224     if((systemState > deviceExtension->SysPower) && (deviceExtension->WaitWakeEnable))
225     {
226         IssueWaitWake(deviceExtension);
227 
228     }
229 
230     IoCopyCurrentIrpStackLocationToNext(Irp);
231     IoSetCompletionRoutine(
232             Irp,
233             (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
234             deviceExtension,
235             TRUE,
236             TRUE,
237             TRUE);
238 
239     ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
240     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Leaving\n"));
241 
242     return STATUS_PENDING;
243 
244 }
245 
HandleSystemSetPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)246 NTSTATUS NTAPI HandleSystemSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
247 {
248     NTSTATUS           ntStatus;
249     PDEVICE_EXTENSION  deviceExtension;
250     SYSTEM_POWER_STATE systemState;
251     PIO_STACK_LOCATION irpStack;
252 
253     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Entered\n"));
254 
255     deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
256     irpStack = IoGetCurrentIrpStackLocation(Irp);
257     systemState = irpStack->Parameters.Power.State.SystemState;
258 
259     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Set request for system power state S%X\n"
260                          "FBTUSB: HandleSystemSetPower: Current system power state S%X\n",
261                          systemState - 1,
262                          deviceExtension->SysPower - 1));
263 
264     IoCopyCurrentIrpStackLocationToNext(Irp);
265     IoSetCompletionRoutine(
266             Irp,
267             (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
268             deviceExtension,
269             TRUE,
270             TRUE,
271             TRUE);
272 
273     ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
274     FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Leaving\n"));
275 
276     return STATUS_PENDING;
277 
278 }
279 
HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject,PIRP Irp)280 NTSTATUS NTAPI HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
281 {
282     NTSTATUS           ntStatus;
283     PDEVICE_EXTENSION  deviceExtension;
284     PIO_STACK_LOCATION irpStack;
285     DEVICE_POWER_STATE deviceState;
286 
287     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Entered\n"));
288 
289     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
290     irpStack = IoGetCurrentIrpStackLocation(Irp);
291     deviceState = irpStack->Parameters.Power.State.DeviceState;
292 
293     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Query for device power state D%X\n"
294                          "FBTUSB: HandleDeviceQueryPower: Current device power state D%X\n",
295                          deviceState - 1,
296                          deviceExtension->DevPower - 1));
297 
298     if (deviceExtension->WaitWakeEnable && deviceState > deviceExtension->DeviceCapabilities.DeviceWake)
299     {
300         PoStartNextPowerIrp(Irp);
301         Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
302         Irp->IoStatus.Information = 0;
303         IoCompleteRequest(Irp, IO_NO_INCREMENT);
304 
305         FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
306         FreeBT_IoDecrement(deviceExtension);
307 
308         return ntStatus;
309 
310     }
311 
312     if (deviceState < deviceExtension->DevPower)
313     {
314         ntStatus = STATUS_SUCCESS;
315 
316     }
317 
318     else
319     {
320         ntStatus = HoldIoRequests(DeviceObject, Irp);
321         if(STATUS_PENDING == ntStatus)
322         {
323             return ntStatus;
324 
325         }
326 
327     }
328 
329     // on error complete the Irp.
330     // on success pass it to the lower layers
331     PoStartNextPowerIrp(Irp);
332     Irp->IoStatus.Status = ntStatus;
333     Irp->IoStatus.Information = 0;
334     if(!NT_SUCCESS(ntStatus))
335     {
336         IoCompleteRequest(Irp, IO_NO_INCREMENT);
337 
338     }
339 
340     else
341     {
342         IoSkipCurrentIrpStackLocation(Irp);
343         ntStatus=PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
344 
345     }
346 
347     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
348     FreeBT_IoDecrement(deviceExtension);
349 
350     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Leaving\n"));
351 
352     return ntStatus;
353 
354 }
355 
356 
SysPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PDEVICE_EXTENSION DeviceExtension)357 NTSTATUS NTAPI SysPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
358 {
359     NTSTATUS           ntStatus;
360     PIO_STACK_LOCATION irpStack;
361 
362     ntStatus = Irp->IoStatus.Status;
363     irpStack = IoGetCurrentIrpStackLocation(Irp);
364 
365     FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Entered\n"));
366 
367     // lower drivers failed this Irp
368     if(!NT_SUCCESS(ntStatus))
369     {
370         PoStartNextPowerIrp(Irp);
371         FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine::"));
372         FreeBT_IoDecrement(DeviceExtension);
373 
374         return STATUS_SUCCESS;
375 
376     }
377 
378     // ..otherwise update the cached system power state (IRP_MN_SET_POWER)
379     if(irpStack->MinorFunction == IRP_MN_SET_POWER)
380     {
381         DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
382 
383     }
384 
385     // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
386     SendDeviceIrp(DeviceObject, Irp);
387 
388     FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Leaving\n"));
389 
390     return STATUS_MORE_PROCESSING_REQUIRED;
391 
392 }
393 
SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP SIrp)394 VOID NTAPI SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP SIrp )
395 {
396     NTSTATUS                  ntStatus;
397     POWER_STATE               powState;
398     PDEVICE_EXTENSION         deviceExtension;
399     PIO_STACK_LOCATION        irpStack;
400     SYSTEM_POWER_STATE        systemState;
401     DEVICE_POWER_STATE        devState;
402     PPOWER_COMPLETION_CONTEXT powerContext;
403 
404     irpStack = IoGetCurrentIrpStackLocation(SIrp);
405     systemState = irpStack->Parameters.Power.State.SystemState;
406     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
407 
408     FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Entered\n"));
409 
410     // Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
411     // we can choose deeper sleep states than our mapping but never choose
412     // lighter ones.
413     devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
414     powState.DeviceState = devState;
415 
416     powerContext = (PPOWER_COMPLETION_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT));
417     if (!powerContext)
418     {
419         FreeBT_DbgPrint(1, ("FBTUSB: SendDeviceIrp: Failed to alloc memory for powerContext\n"));
420         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
421 
422     }
423 
424     else
425     {
426         powerContext->DeviceObject = DeviceObject;
427         powerContext->SIrp = SIrp;
428 
429         // in win2k PoRequestPowerIrp can take fdo or pdo.
430         ntStatus = PoRequestPowerIrp(
431                             deviceExtension->PhysicalDeviceObject,
432                             irpStack->MinorFunction,
433                             powState,
434                             (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
435                             powerContext,
436                             NULL);
437 
438     }
439 
440     if (!NT_SUCCESS(ntStatus))
441     {
442         if (powerContext)
443         {
444             ExFreePool(powerContext);
445 
446         }
447 
448         PoStartNextPowerIrp(SIrp);
449         SIrp->IoStatus.Status = ntStatus;
450         SIrp->IoStatus.Information = 0;
451         IoCompleteRequest(SIrp, IO_NO_INCREMENT);
452 
453         FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp::"));
454         FreeBT_IoDecrement(deviceExtension);
455 
456     }
457 
458     FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Leaving\n"));
459 
460 }
461 
462 
DevPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)463 VOID NTAPI DevPoCompletionRoutine(
464     IN PDEVICE_OBJECT DeviceObject,
465     IN UCHAR MinorFunction,
466     IN POWER_STATE PowerState,
467     IN PVOID Context,
468     IN PIO_STATUS_BLOCK IoStatus
469     )
470 {
471     PIRP                      sIrp;
472     PDEVICE_EXTENSION         deviceExtension;
473     PPOWER_COMPLETION_CONTEXT powerContext;
474 
475     powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
476     sIrp = powerContext->SIrp;
477     deviceExtension = (PDEVICE_EXTENSION) powerContext->DeviceObject->DeviceExtension;
478 
479     FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Entered\n"));
480 
481     sIrp->IoStatus.Status = IoStatus->Status;
482     PoStartNextPowerIrp(sIrp);
483     sIrp->IoStatus.Information = 0;
484     IoCompleteRequest(sIrp, IO_NO_INCREMENT);
485 
486     FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine::"));
487     FreeBT_IoDecrement(deviceExtension);
488 
489     ExFreePool(powerContext);
490 
491     FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Leaving\n"));
492 
493 }
494 
HandleDeviceSetPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)495 NTSTATUS NTAPI HandleDeviceSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
496 {
497     KIRQL              oldIrql;
498     NTSTATUS           ntStatus;
499     POWER_STATE        newState;
500     PIO_STACK_LOCATION irpStack;
501     PDEVICE_EXTENSION  deviceExtension;
502     DEVICE_POWER_STATE newDevState,
503                        oldDevState;
504 
505     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Entered\n"));
506 
507     deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
508     irpStack = IoGetCurrentIrpStackLocation(Irp);
509     oldDevState = deviceExtension->DevPower;
510     newState = irpStack->Parameters.Power.State;
511     newDevState = newState.DeviceState;
512 
513     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Set request for device power state D%X\n"
514                          "FBTUSB: HandleDeviceSetPower: Current device power state D%X\n",
515                          newDevState - 1,
516                          deviceExtension->DevPower - 1));
517 
518     if (newDevState < oldDevState)
519     {
520 
521         FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Adding power to the device\n"));
522 
523         IoCopyCurrentIrpStackLocationToNext(Irp);
524         IoSetCompletionRoutine(
525                 Irp,
526                 (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
527                 deviceExtension,
528                 TRUE,
529                 TRUE,
530                 TRUE);
531 
532         ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
533 
534     }
535 
536     else
537     {
538         // newDevState >= oldDevState
539 
540         // hold I/O if transition from D0 -> DX (X = 1, 2, 3)
541         // if transition from D1 or D2 to deeper sleep states,
542         // I/O queue is already on hold.
543         if(PowerDeviceD0 == oldDevState && newDevState > oldDevState)
544         {
545             // D0 -> DX transition
546             FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Removing power from the device\n"));
547 
548             ntStatus = HoldIoRequests(DeviceObject, Irp);
549             if (!NT_SUCCESS(ntStatus))
550             {
551                 PoStartNextPowerIrp(Irp);
552                 Irp->IoStatus.Status = ntStatus;
553                 Irp->IoStatus.Information = 0;
554                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
555 
556                 FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower::"));
557                 FreeBT_IoDecrement(deviceExtension);
558 
559                 return ntStatus;
560 
561             }
562 
563             else
564             {
565                 goto HandleDeviceSetPower_Exit;
566 
567             }
568 
569         }
570 
571         else if (PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState)
572         {
573             // D0 -> D0
574             // unblock the queue which may have been blocked processing
575             // query irp
576             FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: A SetD0 request\n"));
577 
578             KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
579             deviceExtension->QueueState = AllowRequests;
580             KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
581 
582             ProcessQueuedRequests(deviceExtension);
583 
584         }
585 
586         IoCopyCurrentIrpStackLocationToNext(Irp);
587         IoSetCompletionRoutine(
588                 Irp,
589                 (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
590                 deviceExtension,
591                 TRUE,
592                 TRUE,
593                 TRUE);
594 
595         ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
596         if(!NT_SUCCESS(ntStatus))
597         {
598             FreeBT_DbgPrint(1, ("FBTUSB: HandleDeviceSetPower: Lower drivers failed a power Irp\n"));
599 
600         }
601 
602     }
603 
604 HandleDeviceSetPower_Exit:
605 
606     FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Leaving\n"));
607 
608     return STATUS_PENDING;
609 
610 }
611 
FinishDevPoUpIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PDEVICE_EXTENSION DeviceExtension)612 NTSTATUS NTAPI FinishDevPoUpIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
613 {
614     NTSTATUS           ntStatus;
615 
616     FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Entered\n"));
617 
618     ntStatus = Irp->IoStatus.Status;
619     if(Irp->PendingReturned)
620     {
621         IoMarkIrpPending(Irp);
622 
623     }
624 
625     if(!NT_SUCCESS(ntStatus))
626     {
627         PoStartNextPowerIrp(Irp);
628 
629         FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp::"));
630         FreeBT_IoDecrement(DeviceExtension);
631 
632         return STATUS_SUCCESS;
633 
634     }
635 
636     SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
637 
638     FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Leaving\n"));
639 
640     return STATUS_MORE_PROCESSING_REQUIRED;
641 
642 }
643 
SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PDEVICE_EXTENSION DeviceExtension)644 NTSTATUS NTAPI SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
645 {
646     KIRQL              oldIrql;
647     NTSTATUS           ntStatus;
648     POWER_STATE        newState;
649     PIO_STACK_LOCATION irpStack;
650     DEVICE_POWER_STATE newDevState, oldDevState;
651 
652     ntStatus = Irp->IoStatus.Status;
653     irpStack = IoGetCurrentIrpStackLocation(Irp);
654     newState = irpStack->Parameters.Power.State;
655     newDevState = newState.DeviceState;
656     oldDevState = DeviceExtension->DevPower;
657 
658     FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Entered\n"));
659 
660     // update the cached state
661     DeviceExtension->DevPower = newDevState;
662 
663     // restore appropriate amount of state to our h/w
664     // this driver does not implement partial context
665     // save/restore.
666     PoSetPowerState(DeviceObject, DevicePowerState, newState);
667     if(PowerDeviceD0 == newDevState)
668     {
669         KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
670         DeviceExtension->QueueState = AllowRequests;
671         KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
672 
673         ProcessQueuedRequests(DeviceExtension);
674 
675     }
676 
677     PoStartNextPowerIrp(Irp);
678     Irp->IoStatus.Status = STATUS_SUCCESS;
679     Irp->IoStatus.Information = 0;
680     IoCompleteRequest(Irp, IO_NO_INCREMENT);
681 
682     FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional::"));
683     FreeBT_IoDecrement(DeviceExtension);
684 
685     FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Leaving\n"));
686 
687     return STATUS_SUCCESS;
688 
689 }
690 
FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PDEVICE_EXTENSION DeviceExtension)691 NTSTATUS NTAPI FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
692 {
693     NTSTATUS           ntStatus;
694     POWER_STATE        newState;
695     PIO_STACK_LOCATION irpStack;
696 
697     FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Entered\n"));
698 
699     ntStatus = Irp->IoStatus.Status;
700     irpStack = IoGetCurrentIrpStackLocation(Irp);
701     newState = irpStack->Parameters.Power.State;
702 
703     if (NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER)
704     {
705         FreeBT_DbgPrint(3, ("FBTUSB: updating cache..\n"));
706         DeviceExtension->DevPower = newState.DeviceState;
707         PoSetPowerState(DeviceObject, DevicePowerState, newState);
708 
709     }
710 
711     PoStartNextPowerIrp(Irp);
712 
713     FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp::"));
714     FreeBT_IoDecrement(DeviceExtension);
715 
716     FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Leaving\n"));
717 
718     return STATUS_SUCCESS;
719 
720 }
721 
HoldIoRequests(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)722 NTSTATUS NTAPI HoldIoRequests(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
723 
724 {
725     NTSTATUS               ntStatus;
726     PIO_WORKITEM           item;
727     PDEVICE_EXTENSION      deviceExtension;
728     PWORKER_THREAD_CONTEXT context;
729 
730     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Entered\n"));
731 
732     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
733     deviceExtension->QueueState = HoldRequests;
734 
735     context = (PWORKER_THREAD_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
736     if(context)
737     {
738         item = IoAllocateWorkItem(DeviceObject);
739 
740         context->Irp = Irp;
741         context->DeviceObject = DeviceObject;
742         context->WorkItem = item;
743 
744         if (item)
745         {
746             IoMarkIrpPending(Irp);
747             IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine, DelayedWorkQueue, context);
748             ntStatus = STATUS_PENDING;
749 
750         }
751 
752         else
753         {
754             FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Failed to allocate memory for workitem\n"));
755             ExFreePool(context);
756             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
757 
758         }
759 
760     }
761 
762     else
763     {
764         FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequests: Failed to alloc memory for worker thread context\n"));
765         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
766 
767     }
768 
769     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Leaving\n"));
770 
771     return ntStatus;
772 
773 }
774 
HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context)775 VOID NTAPI HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
776 {
777     PIRP                   irp;
778     NTSTATUS               ntStatus;
779     PDEVICE_EXTENSION      deviceExtension;
780     PWORKER_THREAD_CONTEXT context;
781 
782     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Entered\n"));
783 
784     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
785     context = (PWORKER_THREAD_CONTEXT) Context;
786     irp = (PIRP) context->Irp;
787 
788     // wait for I/O in progress to finish.
789     // the stop event is signalled when the counter drops to 1.
790     // invoke FreeBT_IoDecrement twice: once each for the S-Irp and D-Irp.
791     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
792     FreeBT_IoDecrement(deviceExtension);
793 
794     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
795     FreeBT_IoDecrement(deviceExtension);
796 
797     KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
798 
799     // Increment twice to restore the count
800     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
801     FreeBT_IoIncrement(deviceExtension);
802 
803     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
804     FreeBT_IoIncrement(deviceExtension);
805 
806     // now send the Irp down
807     IoCopyCurrentIrpStackLocationToNext(irp);
808     IoSetCompletionRoutine(
809         irp,
810         (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
811         deviceExtension,
812         TRUE,
813         TRUE,
814         TRUE);
815 
816     ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
817     if(!NT_SUCCESS(ntStatus))
818     {
819         FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequestsWorkerRoutine: Lower driver fail a power Irp\n"));
820 
821     }
822 
823     IoFreeWorkItem(context->WorkItem);
824     ExFreePool((PVOID)context);
825 
826     FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Leaving\n"));
827 
828 }
829 
QueueRequest(IN OUT PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)830 NTSTATUS NTAPI QueueRequest(IN OUT PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp)
831 {
832     KIRQL    oldIrql;
833     NTSTATUS ntStatus;
834 
835     FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Entered\n"));
836 
837     ntStatus = STATUS_PENDING;
838 
839     ASSERT(HoldRequests == DeviceExtension->QueueState);
840 
841     KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
842 
843     InsertTailList(&DeviceExtension->NewRequestsQueue, &Irp->Tail.Overlay.ListEntry);
844     IoMarkIrpPending(Irp);
845     IoSetCancelRoutine(Irp, CancelQueued);
846 
847     KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
848 
849     FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Leaving\n"));
850 
851     return ntStatus;
852 
853 }
854 
CancelQueued(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)855 VOID NTAPI CancelQueued(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
856 {
857     PDEVICE_EXTENSION deviceExtension;
858     KIRQL             oldIrql;
859 
860     FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Entered\n"));
861 
862     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
863     oldIrql = Irp->CancelIrql;
864 
865     // Release the cancel spin lock
866     IoReleaseCancelSpinLock(Irp->CancelIrql);
867 
868     // Acquire the queue lock
869     KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
870 
871     // Remove the cancelled Irp from queue and release the lock
872     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
873 
874     KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
875 
876     // complete with STATUS_CANCELLED
877     Irp->IoStatus.Status = STATUS_CANCELLED;
878     Irp->IoStatus.Information = 0;
879     IoCompleteRequest(Irp, IO_NO_INCREMENT);
880 
881     FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Leaving\n"));
882 
883     return;
884 
885 }
886 
IssueWaitWake(IN PDEVICE_EXTENSION DeviceExtension)887 NTSTATUS NTAPI IssueWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
888 {
889     POWER_STATE poState;
890     NTSTATUS    ntStatus;
891 
892     FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Entered\n"));
893 
894     if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1))
895     {
896         return STATUS_DEVICE_BUSY;
897 
898     }
899 
900     InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
901 
902     // lowest state from which this Irp will wake the system
903     poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
904     ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
905                                  IRP_MN_WAIT_WAKE,
906                                  poState,
907                                  (PREQUEST_POWER_COMPLETE) WaitWakeCallback,
908                                  DeviceExtension,
909                                  &DeviceExtension->WaitWakeIrp);
910 
911     if(!NT_SUCCESS(ntStatus))
912     {
913         InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
914 
915     }
916 
917     FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Leaving\n"));
918 
919     return ntStatus;
920 
921 }
922 
CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension)923 VOID NTAPI CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
924 {
925     PIRP Irp;
926 
927     FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Entered\n"));
928 
929     Irp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->WaitWakeIrp,
930                                             NULL);
931     if(Irp)
932     {
933         IoCancelIrp(Irp);
934         if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
935         {
936             PoStartNextPowerIrp(Irp);
937             Irp->IoStatus.Status = STATUS_CANCELLED;
938             Irp->IoStatus.Information = 0;
939             IoCompleteRequest(Irp, IO_NO_INCREMENT);
940 
941         }
942 
943     }
944 
945     FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Leaving\n"));
946 
947 }
948 
WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PDEVICE_EXTENSION DeviceExtension)949 NTSTATUS NTAPI WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
950 {
951     FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Entered\n"));
952     if(Irp->PendingReturned)
953     {
954         IoMarkIrpPending(Irp);
955 
956     }
957 
958     // Nullify the WaitWakeIrp pointer-the Irp is released
959     // as part of the completion process. If it's already NULL,
960     // avoid race with the CancelWaitWake routine.
961     if(InterlockedExchangePointer((PVOID*)&DeviceExtension->WaitWakeIrp, NULL))
962     {
963         PoStartNextPowerIrp(Irp);
964 
965         return STATUS_SUCCESS;
966 
967     }
968 
969     // CancelWaitWake has run.
970     // If FlagWWCancel != 0, complete the Irp.
971     // If FlagWWCancel == 0, CancelWaitWake completes it.
972     if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
973     {
974         PoStartNextPowerIrp(Irp);
975 
976         return STATUS_CANCELLED;
977 
978     }
979 
980     FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Leaving\n"));
981 
982     return STATUS_MORE_PROCESSING_REQUIRED;
983 
984 }
985 
WaitWakeCallback(IN PDEVICE_OBJECT DeviceObject,IN UCHAR MinorFunction,IN POWER_STATE PowerState,IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus)986 VOID NTAPI WaitWakeCallback(
987     IN PDEVICE_OBJECT DeviceObject,
988     IN UCHAR MinorFunction,
989     IN POWER_STATE PowerState,
990     IN PVOID Context,
991     IN PIO_STATUS_BLOCK IoStatus)
992 {
993     NTSTATUS               ntStatus;
994     POWER_STATE            powerState;
995     PDEVICE_EXTENSION      deviceExtension;
996 
997     FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Entered\n"));
998 
999     deviceExtension = (PDEVICE_EXTENSION) Context;
1000 
1001     InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
1002 
1003     if(!NT_SUCCESS(IoStatus->Status))
1004     {
1005         return;
1006 
1007     }
1008 
1009     // wake up the device
1010     if(deviceExtension->DevPower == PowerDeviceD0)
1011     {
1012         FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Device already powered up...\n"));
1013 
1014         return;
1015 
1016     }
1017 
1018     FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback::"));
1019     FreeBT_IoIncrement(deviceExtension);
1020 
1021     powerState.DeviceState = PowerDeviceD0;
1022     ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
1023                                  IRP_MN_SET_POWER,
1024                                  powerState,
1025                                  (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
1026                                  deviceExtension,
1027                                  NULL);
1028 
1029     if(deviceExtension->WaitWakeEnable)
1030     {
1031         IssueWaitWake(deviceExtension);
1032 
1033     }
1034 
1035     FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Leaving\n"));
1036 
1037     return;
1038 
1039 }
1040 
1041 
PowerMinorFunctionString(IN UCHAR MinorFunction)1042 PCHAR NTAPI PowerMinorFunctionString (IN UCHAR MinorFunction)
1043 {
1044     switch (MinorFunction)
1045     {
1046         case IRP_MN_SET_POWER:
1047             return "IRP_MN_SET_POWER\n";
1048 
1049         case IRP_MN_QUERY_POWER:
1050             return "IRP_MN_QUERY_POWER\n";
1051 
1052         case IRP_MN_POWER_SEQUENCE:
1053             return "IRP_MN_POWER_SEQUENCE\n";
1054 
1055         case IRP_MN_WAIT_WAKE:
1056             return "IRP_MN_WAIT_WAKE\n";
1057 
1058         default:
1059             return "IRP_MN_?????\n";
1060 
1061     }
1062 
1063 }
1064