- merge audio headers
[reactos.git] / drivers / bluetooth / fbtusb / fbtpwr.c
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
23 NTSTATUS FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
24 {
25 NTSTATUS ntStatus;
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
187 NTSTATUS 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
246 NTSTATUS 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
280 NTSTATUS 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
357 NTSTATUS 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
394 VOID 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
463 VOID 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
495 NTSTATUS 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
612 NTSTATUS 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
644 NTSTATUS 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
691 NTSTATUS 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
722 NTSTATUS 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
775 VOID 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
830 NTSTATUS 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
855 VOID 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
887 NTSTATUS 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
923 VOID CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
924 {
925 PIRP Irp;
926
927 FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Entered\n"));
928
929 Irp = (PIRP) InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL);
930 if(Irp)
931 {
932 IoCancelIrp(Irp);
933 if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
934 {
935 PoStartNextPowerIrp(Irp);
936 Irp->IoStatus.Status = STATUS_CANCELLED;
937 Irp->IoStatus.Information = 0;
938 IoCompleteRequest(Irp, IO_NO_INCREMENT);
939
940 }
941
942 }
943
944 FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Leaving\n"));
945
946 }
947
948 NTSTATUS WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
949 {
950 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Entered\n"));
951 if(Irp->PendingReturned)
952 {
953 IoMarkIrpPending(Irp);
954
955 }
956
957 // Nullify the WaitWakeIrp pointer-the Irp is released
958 // as part of the completion process. If it's already NULL,
959 // avoid race with the CancelWaitWake routine.
960 if(InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL))
961 {
962 PoStartNextPowerIrp(Irp);
963
964 return STATUS_SUCCESS;
965
966 }
967
968 // CancelWaitWake has run.
969 // If FlagWWCancel != 0, complete the Irp.
970 // If FlagWWCancel == 0, CancelWaitWake completes it.
971 if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
972 {
973 PoStartNextPowerIrp(Irp);
974
975 return STATUS_CANCELLED;
976
977 }
978
979 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Leaving\n"));
980
981 return STATUS_MORE_PROCESSING_REQUIRED;
982
983 }
984
985 VOID WaitWakeCallback(
986 IN PDEVICE_OBJECT DeviceObject,
987 IN UCHAR MinorFunction,
988 IN POWER_STATE PowerState,
989 IN PVOID Context,
990 IN PIO_STATUS_BLOCK IoStatus)
991 {
992 NTSTATUS ntStatus;
993 POWER_STATE powerState;
994 PDEVICE_EXTENSION deviceExtension;
995
996 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Entered\n"));
997
998 deviceExtension = (PDEVICE_EXTENSION) Context;
999
1000 InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
1001
1002 if(!NT_SUCCESS(IoStatus->Status))
1003 {
1004 return;
1005
1006 }
1007
1008 // wake up the device
1009 if(deviceExtension->DevPower == PowerDeviceD0)
1010 {
1011 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Device already powered up...\n"));
1012
1013 return;
1014
1015 }
1016
1017 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback::"));
1018 FreeBT_IoIncrement(deviceExtension);
1019
1020 powerState.DeviceState = PowerDeviceD0;
1021 ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
1022 IRP_MN_SET_POWER,
1023 powerState,
1024 (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
1025 deviceExtension,
1026 NULL);
1027
1028 if(deviceExtension->WaitWakeEnable)
1029 {
1030 IssueWaitWake(deviceExtension);
1031
1032 }
1033
1034 FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Leaving\n"));
1035
1036 return;
1037
1038 }
1039
1040
1041 PCHAR PowerMinorFunctionString (IN UCHAR MinorFunction)
1042 {
1043 switch (MinorFunction)
1044 {
1045 case IRP_MN_SET_POWER:
1046 return "IRP_MN_SET_POWER\n";
1047
1048 case IRP_MN_QUERY_POWER:
1049 return "IRP_MN_QUERY_POWER\n";
1050
1051 case IRP_MN_POWER_SEQUENCE:
1052 return "IRP_MN_POWER_SEQUENCE\n";
1053
1054 case IRP_MN_WAIT_WAKE:
1055 return "IRP_MN_WAIT_WAKE\n";
1056
1057 default:
1058 return "IRP_MN_?????\n";
1059
1060 }
1061
1062 }