00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
#include "iop.h"
00024
00025
00026
00027
00028
00029 PWCHAR
00030
IopCaptureObjectName (
00031 IN PVOID Object
00032 );
00033
00034
VOID
00035
IopFreePoDeviceNotifyListHead (
00036 PLIST_ENTRY ListHead
00037 );
00038
00039
#ifdef ALLOC_PRAGMA
00040
#pragma alloc_text(PAGE, IopWarmEjectDevice)
00041
#pragma alloc_text(PAGELK, IoBuildPoDeviceNotifyList)
00042
#pragma alloc_text(PAGELK, IoFreePoDeviceNotifyList)
00043
#pragma alloc_text(PAGELK, IopFreePoDeviceNotifyListHead)
00044
#pragma alloc_text(PAGELK, IopCaptureObjectName)
00045
#endif
00046
00047
NTSTATUS
00048 IoBuildPoDeviceNotifyList (
00049 IN OUT
PPO_DEVICE_NOTIFY_ORDER Order
00050 )
00051 {
00052 PLIST_ENTRY link;
00053
PPO_DEVICE_NOTIFY notify;
00054
PDEVICE_NODE node;
00055
PDEVICE_NODE parent;
00056 ULONG noLists, listIndex;
00057 PLIST_ENTRY notifyLists;
00058 LONG maxLevel, level;
00059 UCHAR orderLevel;
00060
PDEVICE_OBJECT nonPaged;
00061
00062
00063
00064
00065
00066
IopAcquireDeviceTreeLock();
00067 RtlZeroMemory (Order,
sizeof (*Order));
00068 Order->DevNodeSequence =
IoDeviceNodeTreeSequence;
00069 InitializeListHead (&Order->Partial);
00070 InitializeListHead (&Order->Rebase);
00071
00072
00073
00074
00075
00076
00077 level = -1;
00078 node =
IopRootDeviceNode;
00079
while (node->
Child) {
00080 node = node->
Child;
00081 level += 1;
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 maxLevel = level;
00101
while (node !=
IopRootDeviceNode) {
00102 notify =
ExAllocatePoolWithTag (
00103
NonPagedPool,
00104
sizeof(
PO_DEVICE_NOTIFY),
00105
IOP_DPWR_TAG
00106 );
00107
00108
if (!notify) {
00109
return STATUS_INSUFFICIENT_RESOURCES;
00110 }
00111
00112 RtlZeroMemory (notify,
sizeof(
PO_DEVICE_NOTIFY));
00113
ASSERT(node->
Notify ==
NULL) ;
00114 node->
Notify = notify;
00115 notify->
Node = node;
00116 notify->
DeviceObject = node->
PhysicalDeviceObject;
00117 notify->
TargetDevice =
IoGetAttachedDevice(node->
PhysicalDeviceObject);
00118 notify->
DriverName =
IopCaptureObjectName(notify->
TargetDevice->
DriverObject);
00119 notify->
DeviceName =
IopCaptureObjectName(notify->
TargetDevice);
00120
ObReferenceObject (notify->
DeviceObject);
00121
ObReferenceObject (notify->
TargetDevice);
00122
00123 orderLevel = 0;
00124
00125
if (notify->
TargetDevice->
DeviceType != FILE_DEVICE_SCREEN &&
00126 notify->
TargetDevice->
DeviceType != FILE_DEVICE_VIDEO) {
00127 orderLevel |=
PO_ORDER_NOT_VIDEO;
00128 }
00129
00130
if (notify->
TargetDevice->
Flags &
DO_POWER_PAGABLE) {
00131 orderLevel |=
PO_ORDER_PAGABLE;
00132 }
00133
00134 notify->
OrderLevel = orderLevel;
00135 notify->
NodeLevel = level;
00136
00137
00138
00139
00140
00141
00142
00143
if (level == 0 &&
00144 node->
InterfaceType != Internal &&
00145 !(node->
Flags &
DNF_HAL_NODE)) {
00146
00147 InsertTailList (&Order->Rebase, ¬ify->
Link);
00148 }
else {
00149 InsertTailList (&Order->Partial, ¬ify->
Link);
00150 }
00151
00152
00153
00154
00155
00156
if (node->
Sibling) {
00157 node = node->
Sibling;
00158
while (node->
Child) {
00159 node = node->
Child;
00160 level += 1;
00161
if (level > maxLevel) {
00162 maxLevel = level;
00163 }
00164 }
00165
00166 }
else {
00167 node = node->
Parent;
00168 level -= 1;
00169 }
00170 }
00171
00172
00173
00174
00175
00176
while (!IsListEmpty(&Order->Rebase)) {
00177 link = Order->Rebase.Flink;
00178 notify = CONTAINING_RECORD (link,
PO_DEVICE_NOTIFY, Link);
00179 RemoveEntryList (¬ify->
Link);
00180 InsertTailList (&Order->Partial, ¬ify->
Link);
00181
00182
00183
00184
00185
00186 node = notify->
Node;
00187 notify->
OrderLevel |=
PO_ORDER_ROOT_ENUM;
00188
00189
00190
00191
00192
00193 parent = node;
00194
while (node->Child) {
00195 node = node->
Child;
00196 }
00197
00198
while (node != parent) {
00199 notify = node->Notify;
00200
if (notify) {
00201 notify->
OrderLevel |=
PO_ORDER_ROOT_ENUM;
00202 }
00203
00204
00205
if (node->Sibling) {
00206 node = node->Sibling;
00207
while (node->Child) {
00208 node = node->Child;
00209 }
00210 }
else {
00211 node = node->Parent;
00212 }
00213 }
00214 }
00215
00216
00217
00218
00219
00220 maxLevel = maxLevel + 1;
00221 noLists = maxLevel * (
PO_ORDER_MAXIMUM + 1);
00222 notifyLists =
ExAllocatePoolWithTag (
00223
NonPagedPool,
00224
sizeof(LIST_ENTRY) * noLists,
00225
IOP_DPWR_TAG
00226 );
00227
00228
if (!notifyLists) {
00229
return STATUS_INSUFFICIENT_RESOURCES;
00230 }
00231
00232
for (listIndex=0; listIndex < noLists; listIndex++) {
00233 InitializeListHead (¬ifyLists[listIndex]);
00234 }
00235
00236 Order->Notify = notifyLists;
00237 Order->MaxLevel = maxLevel;
00238 Order->NoLists = noLists;
00239
00240
00241
00242
00243
00244
while (!IsListEmpty(&Order->Partial)) {
00245 link = Order->Partial.Flink;
00246 notify = CONTAINING_RECORD (link,
PO_DEVICE_NOTIFY, Link);
00247 RemoveEntryList (¬ify->
Link);
00248
00249 orderLevel = notify->
OrderLevel;
00250 listIndex = orderLevel * maxLevel + notify->
NodeLevel;
00251 InsertTailList (¬ifyLists[listIndex], ¬ify->
Link);
00252
00253
00254
00255
00256
00257
00258 nonPaged =
NULL;
00259
if (!(notify->
TargetDevice->
Flags &
DO_POWER_PAGABLE)) {
00260 nonPaged = notify->
TargetDevice;
00261 }
00262
00263
if (nonPaged && (notify->
DeviceObject->
Flags &
DO_POWER_PAGABLE)) {
00264
KeBugCheckEx (
00265 DRIVER_POWER_STATE_FAILURE,
00266 0x100,
00267 (ULONG_PTR) nonPaged,
00268 (ULONG_PTR) notify->
TargetDevice,
00269 (ULONG_PTR) notify->
DeviceObject
00270 );
00271 }
00272
00273
00274
00275
00276
00277
00278
00279 node = notify->
Node;
00280
for (parent = node->
Parent;
00281 parent !=
IopRootDeviceNode;
00282 parent = parent->
Parent) {
00283
00284 notify = parent->
Notify;
00285
ASSERT (notify !=
NULL);
00286
if (notify->
OrderLevel <= orderLevel) {
00287
break;
00288 }
00289
00290
if (nonPaged && (
00291 (notify->
DeviceObject->
Flags &
DO_POWER_PAGABLE) ||
00292 (notify->
TargetDevice->
Flags &
DO_POWER_PAGABLE) )) {
00293
00294
KeBugCheckEx (
00295 DRIVER_POWER_STATE_FAILURE,
00296 0x100,
00297 (ULONG_PTR) nonPaged,
00298 (ULONG_PTR) notify->
TargetDevice,
00299 (ULONG_PTR) notify->
DeviceObject
00300 );
00301 }
00302
00303 RemoveEntryList (¬ify->
Link);
00304
00305 notify->
OrderLevel = orderLevel;
00306 listIndex = orderLevel * maxLevel + notify->
NodeLevel;
00307 InsertTailList (¬ifyLists[listIndex], ¬ify->
Link);
00308 }
00309 }
00310
00311 Order->WarmEjectPdoPointer = &
IopWarmEjectPdo;
00312
00313
00314
00315
00316
00317
return STATUS_SUCCESS;
00318 }
00319
00320
VOID
00321 IopFreePoDeviceNotifyListHead (
00322 PLIST_ENTRY ListHead
00323 )
00324 {
00325 PLIST_ENTRY Link;
00326
PPO_DEVICE_NOTIFY Notify;
00327
PDEVICE_NODE Node;
00328
00329
if (ListHead->Flink) {
00330
while (!IsListEmpty(ListHead)) {
00331 Link = ListHead->Flink;
00332 Notify = CONTAINING_RECORD (Link,
PO_DEVICE_NOTIFY, Link);
00333 RemoveEntryList(&Notify->
Link);
00334
00335 Node = (
PDEVICE_NODE) Notify->
Node;
00336 Node->
Notify =
NULL;
00337
00338
ObDereferenceObject (Notify->
DeviceObject);
00339
ObDereferenceObject (Notify->
TargetDevice);
00340
if (Notify->
DeviceName) {
00341
ExFreePool (Notify->
DeviceName);
00342 }
00343
if (Notify->
DriverName) {
00344
ExFreePool (Notify->
DriverName);
00345 }
00346
ExFreePool(Notify);
00347 }
00348 }
00349 }
00350
00351
VOID
00352 IoFreePoDeviceNotifyList (
00353 IN OUT
PPO_DEVICE_NOTIFY_ORDER Order
00354 )
00355 {
00356 ULONG i;
00357
00358
00359
if (Order->DevNodeSequence) {
00360
00361
00362
00363
00364
IopReleaseDeviceTreeLock();
00365 Order->DevNodeSequence = 0;
00366 }
00367
00368
00369
00370
00371
00372
IopFreePoDeviceNotifyListHead (&Order->Partial);
00373
IopFreePoDeviceNotifyListHead (&Order->Rebase);
00374
if (Order->Notify) {
00375
for (i=0; i < Order->NoLists; i++) {
00376
IopFreePoDeviceNotifyListHead (&Order->Notify[i]);
00377 }
00378
ExFreePool (Order->Notify);
00379 }
00380
00381 RtlZeroMemory (Order,
sizeof (
PO_DEVICE_NOTIFY_ORDER));
00382 }
00383
00384
00385 PWCHAR
00386 IopCaptureObjectName (
00387 IN PVOID Object
00388 )
00389 {
00390
NTSTATUS Status;
00391 UCHAR
Buffer[512];
00392 POBJECT_NAME_INFORMATION ObName;
00393 ULONG len;
00394 PWCHAR
Name;
00395
00396 ObName = (POBJECT_NAME_INFORMATION)
Buffer;
00397
Status =
ObQueryNameString (
00398 Object,
00399 ObName,
00400
sizeof (
Buffer),
00401 &len
00402 );
00403
00404
Name =
NULL;
00405
if (
NT_SUCCESS(
Status) && ObName->Name.Buffer) {
00406
Name =
ExAllocatePoolWithTag (
00407
NonPagedPool,
00408 ObName->Name.Length +
sizeof(WCHAR),
00409
IOP_DPWR_TAG
00410 );
00411
00412
if (
Name) {
00413 memcpy (
Name, ObName->Name.Buffer, ObName->Name.Length);
00414
Name[ObName->Name.Length/
sizeof(WCHAR)] = 0;
00415 }
00416 }
00417
00418
return Name;
00419 }
00420
00421
NTSTATUS
00422 IopWarmEjectDevice(
00423 IN
PDEVICE_OBJECT DeviceToEject,
00424 IN SYSTEM_POWER_STATE LightestSleepState
00425 )
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 {
00447
NTSTATUS status;
00448
00449
PAGED_CODE();
00450
00451
00452
00453
00454
00455
00456 status =
KeWaitForSingleObject(
00457 &
IopWarmEjectLock,
00458
Executive,
00459
KernelMode,
00460
FALSE,
00461
NULL
00462 );
00463
00464
ASSERT(status == STATUS_SUCCESS) ;
00465
00466
00467
00468
00469
00470
IopAcquireDeviceTreeLock();
00471
00472
00473
00474
00475
ASSERT(
IopWarmEjectPdo ==
NULL);
00476
IopWarmEjectPdo = DeviceToEject;
00477
00478
00479
00480
00481
IopReleaseDeviceTreeLock();
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
IoDeviceNodeTreeSequence++;
00494
00495
00496
00497
00498 status = NtInitiatePowerAction(
00499 PowerActionWarmEject,
00500 LightestSleepState,
00501 POWER_ACTION_QUERY_ALLOWED |
00502 POWER_ACTION_UI_ALLOWED,
00503
FALSE
00504 );
00505
00506
00507
00508
00509
00510
IopAcquireDeviceTreeLock();
00511
00512
00513
00514
00515
00516
if (
IopWarmEjectPdo) {
00517
00518
if (
NT_SUCCESS(status)) {
00519
00520
00521
00522
00523
00524
ASSERT(0);
00525 status = STATUS_UNSUCCESSFUL;
00526 }
00527
00528
IopWarmEjectPdo =
NULL;
00529 }
00530
00531
00532
00533
00534
IopReleaseDeviceTreeLock();
00535
00536
00537
00538
00539
KeSetEvent(
00540 &
IopWarmEjectLock,
00541
IO_NO_INCREMENT,
00542
FALSE
00543 );
00544
00545
return status;
00546 }
00547
00548