Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

pnppower.c File Reference

#include "iop.h"

Go to the source code of this file.

Functions

PWCHAR IopCaptureObjectName (IN PVOID Object)
VOID IopFreePoDeviceNotifyListHead (PLIST_ENTRY ListHead)
NTSTATUS IoBuildPoDeviceNotifyList (IN OUT PPO_DEVICE_NOTIFY_ORDER Order)
VOID IoFreePoDeviceNotifyList (IN OUT PPO_DEVICE_NOTIFY_ORDER Order)
NTSTATUS IopWarmEjectDevice (IN PDEVICE_OBJECT DeviceToEject, IN SYSTEM_POWER_STATE LightestSleepState)


Function Documentation

NTSTATUS IoBuildPoDeviceNotifyList IN OUT PPO_DEVICE_NOTIFY_ORDER  Order  ) 
 

Definition at line 48 of file pnppower.c.

References ASSERT, _DEVICE_NODE::Child, _PO_DEVICE_NOTIFY::DeviceName, _PO_DEVICE_NOTIFY::DeviceObject, _DEVICE_OBJECT::DeviceType, DNF_HAL_NODE, DO_POWER_PAGABLE, _PO_DEVICE_NOTIFY::DriverName, _DEVICE_OBJECT::DriverObject, ExAllocatePoolWithTag, _DEVICE_NODE::Flags, _DEVICE_OBJECT::Flags, _DEVICE_NODE::InterfaceType, IoDeviceNodeTreeSequence, IoGetAttachedDevice(), IOP_DPWR_TAG, IopAcquireDeviceTreeLock, IopCaptureObjectName(), IopRootDeviceNode, IopWarmEjectPdo, KeBugCheckEx(), _PO_DEVICE_NOTIFY::Link, _PO_DEVICE_NOTIFY::Node, _PO_DEVICE_NOTIFY::NodeLevel, NonPagedPool, _DEVICE_NODE::Notify, NULL, ObReferenceObject, _PO_DEVICE_NOTIFY::OrderLevel, _DEVICE_NODE::Parent, _DEVICE_NODE::PhysicalDeviceObject, PO_DEVICE_NOTIFY, PO_ORDER_MAXIMUM, PO_ORDER_NOT_VIDEO, PO_ORDER_PAGABLE, PO_ORDER_ROOT_ENUM, PPO_DEVICE_NOTIFY, PPO_DEVICE_NOTIFY_ORDER, _DEVICE_NODE::Sibling, and _PO_DEVICE_NOTIFY::TargetDevice.

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 // Acquire device node lock 00064 // 00065 00066 IopAcquireDeviceTreeLock(); 00067 RtlZeroMemory (Order, sizeof (*Order)); 00068 Order->DevNodeSequence = IoDeviceNodeTreeSequence; 00069 InitializeListHead (&Order->Partial); 00070 InitializeListHead (&Order->Rebase); 00071 00072 // 00073 // Allocate notification structures for all nodes, and determine 00074 // maximum depth. 00075 // 00076 00077 level = -1; 00078 node = IopRootDeviceNode; 00079 while (node->Child) { 00080 node = node->Child; 00081 level += 1; 00082 } 00083 00084 // 00085 // ADRIAO 01/12/1999 N.B. - 00086 // 00087 // Note that we include devices without the started flag. Now, we acquire 00088 // the tree lock exclusively, which prevents people from being in the middle 00089 // of a rebalance (actually it doesn't today - this is a bug!). However, two 00090 // things prevent us from excluding devices that aren't started: 00091 // 1) We must be able to send power messages to a device we are warm 00092 // undocking. 00093 // 2) Many devices may not be started, that is no guarentee they are in D3! 00094 // For example, they could easily have a boot config, and PNP still 00095 // relies heavily on BIOS boot configs to keep us from placing hardware 00096 // ontop of other devices with boot configs we haven't found or started 00097 // yet! 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 // If this is a level 0 node it's in the root. Look for 00139 // non-bus stuff in the root as those guys need to be re-based 00140 // below everything else 00141 // 00142 00143 if (level == 0 && 00144 node->InterfaceType != Internal && 00145 !(node->Flags & DNF_HAL_NODE)) { 00146 00147 InsertTailList (&Order->Rebase, &notify->Link); 00148 } else { 00149 InsertTailList (&Order->Partial, &notify->Link); 00150 } 00151 00152 // 00153 // Next node 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 // Rebase anything on the rebase list to be after the normal pnp stuff 00174 // 00175 00176 while (!IsListEmpty(&Order->Rebase)) { 00177 link = Order->Rebase.Flink; 00178 notify = CONTAINING_RECORD (link, PO_DEVICE_NOTIFY, Link); 00179 RemoveEntryList (&notify->Link); 00180 InsertTailList (&Order->Partial, &notify->Link); 00181 00182 // 00183 // Rebase this node 00184 // 00185 00186 node = notify->Node; 00187 notify->OrderLevel |= PO_ORDER_ROOT_ENUM; 00188 00189 // 00190 // Now rebase all the node's children 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 // next node 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 // Allocate ordered notifcation lists 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 (&notifyLists[listIndex]); 00234 } 00235 00236 Order->Notify = notifyLists; 00237 Order->MaxLevel = maxLevel; 00238 Order->NoLists = noLists; 00239 00240 // 00241 // Build ordered list 00242 // 00243 00244 while (!IsListEmpty(&Order->Partial)) { 00245 link = Order->Partial.Flink; 00246 notify = CONTAINING_RECORD (link, PO_DEVICE_NOTIFY, Link); 00247 RemoveEntryList (&notify->Link); 00248 00249 orderLevel = notify->OrderLevel; 00250 listIndex = orderLevel * maxLevel + notify->NodeLevel; 00251 InsertTailList (&notifyLists[listIndex], &notify->Link); 00252 00253 // 00254 // Sanity check that the pagable bit is set the same on the top 00255 // of the PDO stack and the bottom of it 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 // Make sure all parents are at least the level of this child 00276 // node or better 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 (&notify->Link); 00304 00305 notify->OrderLevel = orderLevel; 00306 listIndex = orderLevel * maxLevel + notify->NodeLevel; 00307 InsertTailList (&notifyLists[listIndex], &notify->Link); 00308 } 00309 } 00310 00311 Order->WarmEjectPdoPointer = &IopWarmEjectPdo; 00312 00313 // 00314 // The device tree lock is release when the notify list is freed 00315 // 00316 00317 return STATUS_SUCCESS; 00318 }

VOID IoFreePoDeviceNotifyList IN OUT PPO_DEVICE_NOTIFY_ORDER  Order  ) 
 

Definition at line 352 of file pnppower.c.

References ExFreePool(), IopFreePoDeviceNotifyListHead(), IopReleaseDeviceTreeLock, and PO_DEVICE_NOTIFY_ORDER.

00355 { 00356 ULONG i; 00357 00358 00359 if (Order->DevNodeSequence) { 00360 // 00361 // Release the device tree lock 00362 // 00363 00364 IopReleaseDeviceTreeLock(); 00365 Order->DevNodeSequence = 0; 00366 } 00367 00368 // 00369 // Free the resources from the notify list 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 }

PWCHAR IopCaptureObjectName IN PVOID  Object  ) 
 

Definition at line 386 of file pnppower.c.

References Buffer, ExAllocatePoolWithTag, IOP_DPWR_TAG, Name, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObQueryNameString(), and Status.

Referenced by IoBuildPoDeviceNotifyList().

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 }

VOID IopFreePoDeviceNotifyListHead PLIST_ENTRY  ListHead  ) 
 

Definition at line 321 of file pnppower.c.

References _PO_DEVICE_NOTIFY::DeviceName, _PO_DEVICE_NOTIFY::DeviceObject, _PO_DEVICE_NOTIFY::DriverName, ExFreePool(), _PO_DEVICE_NOTIFY::Link, _PO_DEVICE_NOTIFY::Node, _DEVICE_NODE::Notify, NULL, ObDereferenceObject, and _PO_DEVICE_NOTIFY::TargetDevice.

Referenced by IoFreePoDeviceNotifyList().

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 }

NTSTATUS IopWarmEjectDevice IN PDEVICE_OBJECT  DeviceToEject,
IN SYSTEM_POWER_STATE  LightestSleepState
 

Definition at line 422 of file pnppower.c.

References ASSERT, Executive, FALSE, IO_NO_INCREMENT, IoDeviceNodeTreeSequence, IopAcquireDeviceTreeLock, IopReleaseDeviceTreeLock, IopWarmEjectLock, IopWarmEjectPdo, KernelMode, KeSetEvent(), KeWaitForSingleObject(), NT_SUCCESS, NTSTATUS(), NULL, and PAGED_CODE.

Referenced by IopProcessCompletedEject().

00428 : 00429 00430 This function is invoked to initiate a warm eject. The eject progresses 00431 from S1 to the passed in lightest sleep state. 00432 00433 Arguments: 00434 00435 DeviceToEject - The device to eject 00436 00437 LightestSleepState - The lightest S state (at least S1) that the device 00438 may be ejected in. This might be S4 if we are truely 00439 low on power. 00440 00441 Return Value: 00442 00443 NTSTATUS value. 00444 00445 --*/ 00446 { 00447 NTSTATUS status; 00448 00449 PAGED_CODE(); 00450 00451 // 00452 // Acquire the warm eject device lock. A warm eject requires we enter a 00453 // specific S-state, and two different devices may have conflicting options. 00454 // Therefore only one is allowed to occur at once. 00455 // 00456 status = KeWaitForSingleObject( 00457 &IopWarmEjectLock, 00458 Executive, 00459 KernelMode, 00460 FALSE, 00461 NULL 00462 ); 00463 00464 ASSERT(status == STATUS_SUCCESS) ; 00465 00466 // 00467 // Acquire device node lock. We are not allowed to set or clear this field 00468 // unless we are under this lock. 00469 // 00470 IopAcquireDeviceTreeLock(); 00471 00472 // 00473 // Set the current Pdo to eject. 00474 // 00475 ASSERT(IopWarmEjectPdo == NULL); 00476 IopWarmEjectPdo = DeviceToEject; 00477 00478 // 00479 // Release the tree lock. 00480 // 00481 IopReleaseDeviceTreeLock(); 00482 00483 // 00484 // Attempt to invalidate Po's cached notification list. This should cause 00485 // IoBuildPoDeviceNotifyList to be called at which time it will in theory 00486 // pickup the above placed warm eject Pdo. 00487 // 00488 // ADRIAO NOTE 01/07/1999 - 00489 // Actually, this whole IoDeviceNodeTreeSequence stuff isn't neccessary. 00490 // PnP will make no changes to the tree while the device tree lock is owned, 00491 // and it's owned for the duration of a power notification. 00492 // 00493 IoDeviceNodeTreeSequence++; 00494 00495 // 00496 // Sleep... 00497 // 00498 status = NtInitiatePowerAction( 00499 PowerActionWarmEject, 00500 LightestSleepState, 00501 POWER_ACTION_QUERY_ALLOWED | 00502 POWER_ACTION_UI_ALLOWED, 00503 FALSE // Asynchronous == FALSE 00504 ); 00505 00506 // 00507 // Acquire device node lock. We are not allowed to set or clear this field 00508 // unless we are under this lock. 00509 // 00510 IopAcquireDeviceTreeLock(); 00511 00512 // 00513 // Clear the current PDO to eject, and see if the Pdo was actually picked 00514 // up. 00515 // 00516 if (IopWarmEjectPdo) { 00517 00518 if (NT_SUCCESS(status)) { 00519 00520 // 00521 // If our device wasn't picked up, the return of 00522 // NtInitiatePowerAction should *not* be successful! 00523 // 00524 ASSERT(0); 00525 status = STATUS_UNSUCCESSFUL; 00526 } 00527 00528 IopWarmEjectPdo = NULL; 00529 } 00530 00531 // 00532 // Release the tree lock. 00533 // 00534 IopReleaseDeviceTreeLock(); 00535 00536 // 00537 // Release the warm eject device lock 00538 // 00539 KeSetEvent( 00540 &IopWarmEjectLock, 00541 IO_NO_INCREMENT, 00542 FALSE 00543 ); 00544 00545 return status; 00546 }


Generated on Sat May 15 19:45:14 2004 for test by doxygen 1.3.7