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

pnpenum.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1996 Microsoft Corporation 00004 00005 Module Name: 00006 00007 enum.c 00008 00009 Abstract: 00010 00011 This module contains routines to perform device enumeration 00012 00013 Author: 00014 00015 Shie-Lin Tzong (shielint) Sept. 5, 1996. 00016 00017 Revision History: 00018 00019 James Cavalaris (t-jcaval) July 29, 1997. 00020 Added IopProcessCriticalDeviceRoutine. 00021 00022 --*/ 00023 00024 #include "iop.h" 00025 #pragma hdrstop 00026 #include <setupblk.h> 00027 00028 #ifdef POOL_TAGGING 00029 #undef ExAllocatePool 00030 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'nepP') 00031 #endif 00032 00033 typedef struct _DRIVER_LIST_ENTRY DRIVER_LIST_ENTRY, *PDRIVER_LIST_ENTRY; 00034 00035 struct _DRIVER_LIST_ENTRY { 00036 PDRIVER_OBJECT DriverObject; 00037 PDRIVER_LIST_ENTRY NextEntry; 00038 }; 00039 00040 typedef enum _ADD_DRIVER_STAGE { 00041 LowerDeviceFilters, 00042 LowerClassFilters, 00043 DeviceService, 00044 UpperDeviceFilters, 00045 UpperClassFilters, 00046 MaximumAddStage 00047 } ADD_DRIVER_STAGE; 00048 00049 typedef struct { 00050 PDEVICE_NODE DeviceNode; 00051 00052 BOOLEAN LoadDriver; 00053 00054 PADD_CONTEXT AddContext; 00055 00056 PDRIVER_LIST_ENTRY DriverLists[MaximumAddStage]; 00057 } QUERY_CONTEXT, *PQUERY_CONTEXT; 00058 00059 #if 0 00060 #define ASSERT_INITED(x) \ 00061 ASSERTMSG("DO_DEVICE_INITIALIZING not cleared on device object", \ 00062 ((((x)->Flags) & DO_DEVICE_INITIALIZING) == 0)) 00063 #else 00064 #if DBG 00065 #define ASSERT_INITED(x) \ 00066 if (((x)->Flags & DO_DEVICE_INITIALIZING) != 0) \ 00067 DbgPrint("DO_DEVICE_INITIALIZING flag not cleared on DO %#08lx\n", x); 00068 #else 00069 #define ASSERT_INITED(x) /* nothing */ 00070 #endif 00071 #endif 00072 00073 00074 NTSTATUS 00075 IopBusCheck( 00076 IN PDEVICE_OBJECT DeviceObject, 00077 IN BOOLEAN LoadDriver, 00078 IN BOOLEAN AsyncOk 00079 ); 00080 00081 VOID 00082 IopDeviceActionWorker ( 00083 PVOID Context 00084 ); 00085 00086 NTSTATUS 00087 IopEnumerateDevice( 00088 IN PDEVICE_OBJECT DeviceObject, 00089 IN PSTART_CONTEXT StartContext, 00090 IN BOOLEAN AsyncOk 00091 ); 00092 00093 NTSTATUS 00094 IopCallDriverAddDeviceQueryRoutine( 00095 IN PWSTR ValueName, 00096 IN ULONG ValueType, 00097 IN PWCHAR ValueData, 00098 IN ULONG ValueLength, 00099 IN PQUERY_CONTEXT Context, 00100 IN ULONG ServiceType 00101 ); 00102 00103 NTSTATUS 00104 IopProcessCriticalDeviceRoutine( 00105 IN HANDLE hDevInstance, 00106 IN PBOOLEAN FoundMatch, 00107 IN PUNICODE_STRING ServiceName, 00108 IN PUNICODE_STRING ClassGuid, 00109 IN PUNICODE_STRING LowerFilters, 00110 IN PUNICODE_STRING UpperFilters 00111 ); 00112 00113 BOOLEAN 00114 IopProcessCriticalDevice( 00115 IN PDEVICE_NODE DeviceNode 00116 ); 00117 00118 NTSTATUS 00119 IopProcessNewChildren( 00120 IN PDEVICE_NODE DeviceNode, 00121 IN PSTART_CONTEXT StartContext 00122 ); 00123 00124 NTSTATUS 00125 IopProcessStartDevicesWorker ( 00126 IN PDEVICE_NODE DeviceNode, 00127 OUT PVOID Context 00128 ); 00129 00130 USHORT 00131 IopGetBusTypeGuidIndex( 00132 IN LPGUID busTypeGuid 00133 ); 00134 00135 BOOLEAN 00136 IopFixupDeviceId( 00137 PWCHAR DeviceId 00138 ); 00139 00140 BOOLEAN 00141 IopFixupIds( 00142 IN PWCHAR Ids, 00143 IN ULONG Length 00144 ); 00145 00146 BOOLEAN 00147 IopGetRegistryDwordWithFallback( 00148 IN PUNICODE_STRING valueName, 00149 IN HANDLE PrimaryKey, 00150 IN HANDLE SecondaryKey, 00151 IN OUT PULONG Value); 00152 00153 PSECURITY_DESCRIPTOR 00154 IopGetRegistrySecurityWithFallback( 00155 IN PUNICODE_STRING valueName, 00156 IN HANDLE PrimaryKey, 00157 IN HANDLE SecondaryKey); 00158 00159 NTSTATUS 00160 IopChangeDeviceObjectFromRegistryProperties( 00161 IN PDEVICE_OBJECT PhysicalDeviceObject, 00162 IN HANDLE DeviceClassPropKey, 00163 IN HANDLE DevicePropKey, 00164 IN BOOLEAN UsePdoCharacteristics 00165 ); 00166 00167 #if DBG_SCOPE 00168 ULONG PnpEnumDebugLevel = 0; 00169 #define DebugPrint(level, x) \ 00170 if (level <= PnpEnumDebugLevel) { \ 00171 DbgPrint x; \ 00172 } 00173 #else 00174 #define DebugPrint(level, x) /* x */ 00175 #endif 00176 00177 #ifdef ALLOC_PRAGMA 00178 #pragma alloc_text(PAGE, IopBusCheck) 00179 #pragma alloc_text(PAGE, IopEnumerateDevice) 00180 #pragma alloc_text(PAGE, IopProcessNewDeviceNode) 00181 #pragma alloc_text(PAGE, IopCallDriverAddDevice) 00182 #pragma alloc_text(PAGE, IopGetBusTypeGuidIndex) 00183 #pragma alloc_text(PAGE, IopFixupDeviceId) 00184 #pragma alloc_text(PAGE, IopFixupIds) 00185 #pragma alloc_text(PAGE, IopProcessStartDevices) 00186 #pragma alloc_text(PAGE, IopProcessStartDevicesWorker) 00187 #pragma alloc_text(PAGE, IopStartAndEnumerateDevice) 00188 #endif 00189 00190 // 00191 // This flag indicates if the device's InvalidateDeviceRelation is in progress. 00192 // To read or write this flag, callers must get IopPnpSpinlock. 00193 // 00194 00195 BOOLEAN IopEnumerationInProgress = FALSE; 00196 WORK_QUEUE_ITEM IopDeviceEnumerationWorkItem; 00197 00198 00199 // 00200 // Internal constant strings 00201 // 00202 00203 #define DEVICE_PREFIX_STRING TEXT("\\Device\\") 00204 #define DOSDEVICES_PREFIX_STRING TEXT("\\DosDevices\\") 00205 00206 NTSTATUS 00207 IopRequestDeviceAction( 00208 IN PDEVICE_OBJECT DeviceObject OPTIONAL, 00209 IN DEVICE_REQUEST_TYPE RequestType, 00210 IN PKEVENT CompletionEvent OPTIONAL, 00211 IN PNTSTATUS CompletionStatus OPTIONAL 00212 ) 00213 00214 /*++ 00215 00216 Routine Description: 00217 00218 This routine queues a work item to enumerate a device. This is for IO 00219 internal use only. 00220 00221 Arguments: 00222 00223 DeviceObject - Supplies a pointer to the device object to be enumerated. 00224 if NULL, this is a request to retry resources allocation 00225 failed devices. 00226 00227 Request - the reason for the enumeration. 00228 00229 Return Value: 00230 00231 NTSTATUS code. 00232 00233 --*/ 00234 00235 { 00236 PPI_DEVICE_REQUEST request; 00237 PDEVICE_NODE deviceNode; 00238 KIRQL oldIrql; 00239 00240 // 00241 // If this node is ready for enumeration, enqueue it 00242 // 00243 00244 request = ExAllocatePool(NonPagedPool, sizeof(PI_DEVICE_REQUEST)); 00245 00246 if (request) { 00247 // 00248 // Put this request onto the pending list 00249 // 00250 00251 if (DeviceObject) { 00252 ObReferenceObject(DeviceObject); 00253 } 00254 00255 request->DeviceObject = DeviceObject; 00256 request->RequestType = RequestType; 00257 request->CompletionEvent = CompletionEvent; 00258 request->CompletionStatus = (RequestType == ReenumerateBootDevices)? NULL : CompletionStatus; 00259 00260 InitializeListHead(&request->ListEntry); 00261 00262 // 00263 // Insert the request to the request queue. If the request queue is 00264 // not currently being worked on, request a worker thread to start it. 00265 // 00266 00267 ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql); 00268 00269 InsertTailList(&IopPnpEnumerationRequestList, &request->ListEntry); 00270 00271 if ( RequestType == ReenumerateBootDevices || 00272 RequestType == ReenumerateRootDevices) { 00273 // 00274 // This is a special request used when booting the system. Instead 00275 // of queuing a work item it synchronously calls the work routine. 00276 // 00277 00278 IopEnumerationInProgress = TRUE; 00279 KeClearEvent(&PiEnumerationLock); 00280 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00281 00282 IopDeviceActionWorker((PVOID)CompletionStatus); 00283 00284 } else if (PnPBootDriversLoaded && !IopEnumerationInProgress) { 00285 IopEnumerationInProgress = TRUE; 00286 KeClearEvent(&PiEnumerationLock); 00287 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00288 00289 // 00290 // Queue a work item to do the enumeration 00291 // 00292 00293 ExInitializeWorkItem(&IopDeviceEnumerationWorkItem, IopDeviceActionWorker, NULL); 00294 ExQueueWorkItem(&IopDeviceEnumerationWorkItem, DelayedWorkQueue); 00295 } else { 00296 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00297 } 00298 } else { 00299 return STATUS_INSUFFICIENT_RESOURCES; 00300 } 00301 00302 return STATUS_SUCCESS; 00303 } 00304 00305 00306 VOID 00307 IopDeviceActionWorker( 00308 PVOID Context 00309 ) 00310 00311 /*++ 00312 00313 Routine Description: 00314 00315 This routine is the worker routine of ZwLoadDriver. 00316 Its main purpose is to start and enumerate the device controlled by the newly 00317 loaded drivers. 00318 00319 Caller must obtain a reference of the *new* device object. 00320 00321 Parameters: 00322 00323 Context - Supplies a pointer to the BUS_CHECK_WORK_ITEM. 00324 00325 ReturnValue: 00326 00327 None. 00328 00329 --*/ 00330 00331 { 00332 PPI_DEVICE_REQUEST request; 00333 PDEVICE_OBJECT deviceObject; 00334 PDEVICE_NODE deviceNode; 00335 PLIST_ENTRY entry; 00336 BOOLEAN assignResources = FALSE, allocateResources = FALSE; 00337 BOOLEAN bootConfigsOK = TRUE, bootProcess = FALSE; 00338 BOOLEAN newDevice, moreProcessing; 00339 START_CONTEXT startContext; 00340 KIRQL oldIrql; 00341 NTSTATUS status = STATUS_UNSUCCESSFUL; 00342 00343 PAGED_CODE(); 00344 00345 for (; ;) { 00346 00347 ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql); 00348 entry = RemoveHeadList(&IopPnpEnumerationRequestList); 00349 if (entry == &IopPnpEnumerationRequestList) { 00350 entry = NULL; 00351 } 00352 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00353 00354 if (!entry) { 00355 00356 // 00357 // BUGBUG 00358 // 00359 // This code will get run whenever we remove a device (amongst other 00360 // situations). However, if we are trying to start boot devices, we 00361 // don't want to start other devices. The startContext should 00362 // probably be based on some global state that knows what devices 00363 // should be (and more importantly should not be) started. 00364 // 00365 if ((allocateResources && IopResourcesReleased) || assignResources || bootProcess) { 00366 00367 // 00368 // Retry resource allocation for the DNF_INSUFFICIENT_RESOURCES devices 00369 // if there are new resources become available. 00370 // 00371 00372 newDevice = TRUE; 00373 00374 startContext.LoadDriver = PnPBootDriversInitialized; 00375 startContext.AddContext.GroupsToStart = NO_MORE_GROUP; 00376 startContext.AddContext.GroupToStartNext = NO_MORE_GROUP; 00377 startContext.AddContext.DriverStartType = SERVICE_DEMAND_START; 00378 00379 do { 00380 00381 startContext.NewDevice = FALSE; 00382 00383 // 00384 // Process the whole device tree to assign resources to those devices who 00385 // have been successfully added to their drivers. 00386 // 00387 00388 moreProcessing = IopProcessAssignResources(IopRootDeviceNode, newDevice, bootConfigsOK); 00389 00390 // 00391 // Process the device subtree to start those devices who have been allocated 00392 // resources and waiting to be started. 00393 // Note, the IopProcessStartDevices routine may enumerate new devices. 00394 // 00395 00396 IopProcessStartDevices(IopRootDeviceNode, &startContext); 00397 newDevice = startContext.NewDevice; 00398 00399 } while ((moreProcessing || newDevice) && !bootProcess); 00400 00401 allocateResources = FALSE; 00402 assignResources = FALSE; 00403 bootProcess = FALSE; 00404 IopResourcesReleased = FALSE; // This flag is set on device removal 00405 00406 } else { 00407 00408 ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql); 00409 00410 if (IsListEmpty(&IopPnpEnumerationRequestList)) { 00411 IopEnumerationInProgress = FALSE; 00412 KeSetEvent(&PiEnumerationLock, 0, FALSE); 00413 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00414 return; 00415 } 00416 00417 ExReleaseSpinLock(&IopPnPSpinLock, oldIrql); 00418 } 00419 00420 continue; 00421 } 00422 00423 request = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry); 00424 if (request->DeviceObject == NULL) { 00425 00426 // 00427 // This is a request to retry resource allocation for the 00428 // DNF_INSUFFICIENT_RESOURCES or ResourceRequirementsChanged devices 00429 // 00430 00431 if (request->RequestType == ReenumerateBootDevices) { 00432 00433 // 00434 // Indicate that this is during boot driver initialization phase. 00435 // 00436 00437 bootProcess = TRUE; 00438 00439 // 00440 // Get whether this driver allows BOOT config assignment at its level. 00441 // 00442 00443 if (Context) { 00444 00445 bootConfigsOK = *(PBOOLEAN)Context; 00446 00447 } 00448 00449 } else if (request->RequestType == ResourceRequirementsChanged) { 00450 // 00451 // The device wasn't started when IopResourceRequirementsChanged 00452 // was called. 00453 // 00454 assignResources = TRUE; 00455 } else { 00456 // 00457 // Resources were freed we want to try to satisfy any 00458 // DNF_INSUFFICIENT_RESOURCES devices. 00459 // 00460 allocateResources = TRUE; 00461 } 00462 ExFreePool(request); 00463 00464 // 00465 // We've set the flags, we'll do the actual work once we've 00466 // processed any other requests in the queue. 00467 // 00468 continue; 00469 } 00470 00471 if (request->RequestType == ResourceRequirementsChanged) { 00472 00473 deviceObject = request->DeviceObject; 00474 00475 // 00476 // Enumerate this object 00477 // 00478 00479 IopReallocateResources(deviceObject); 00480 00481 } else if (request->RequestType == StartDevice) { 00482 00483 PNEW_DEVICE_WORK_ITEM newDeviceWorkItem; 00484 PDEVICE_NODE parentNode; 00485 00486 deviceObject = request->DeviceObject; 00487 deviceNode = deviceObject->DeviceObjectExtension->DeviceNode; 00488 00489 // 00490 // Start the specific device (reenumeration of parent not required in 00491 // this case) by first registering it then calling kernel-mode new 00492 // dev routine (note that this routine is normally called via a work 00493 // item but we're already in a work item now so call it directly. 00494 // 00495 00496 ASSERT(deviceNode); 00497 00498 // 00499 // Make sure we don't step on another enumerator's toes 00500 // 00501 00502 IopAcquireDeviceTreeLock(); 00503 00504 KeEnterCriticalRegion(); 00505 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 00506 00507 parentNode = deviceNode->Parent; 00508 if (parentNode != NULL) { 00509 ObReferenceObject(parentNode->PhysicalDeviceObject); 00510 } 00511 00512 ExReleaseResource(&PpRegistryDeviceResource); 00513 KeLeaveCriticalRegion(); 00514 00515 IopReleaseDeviceTreeLock(); 00516 00517 if (parentNode == NULL) { 00518 status = STATUS_UNSUCCESSFUL; 00519 goto Clean0; 00520 } 00521 00522 IopAcquireEnumerationLock(parentNode); 00523 00524 if (deviceNode->Flags & DNF_STARTED) { 00525 00526 IopReleaseEnumerationLock(parentNode); 00527 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00528 status = STATUS_SUCCESS; 00529 goto Clean0; 00530 } 00531 00532 if ((parentNode->Parent == NULL && parentNode != IopRootDeviceNode) || 00533 !(parentNode->Flags & DNF_STARTED) || 00534 !(deviceNode->Flags & DNF_ENUMERATED) || 00535 IopDoesDevNodeHaveProblem(deviceNode) || 00536 (deviceNode->Flags & DNF_ADDED) || 00537 deviceNode->LockCount != 0) { 00538 00539 // 00540 // If the parent or child is going away bail now. 00541 // 00542 IopReleaseEnumerationLock(parentNode); 00543 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00544 status = STATUS_UNSUCCESSFUL; 00545 goto Clean0; 00546 } 00547 00548 IopRestartDeviceNode(deviceNode); 00549 00550 status = IopProcessNewDeviceNode(deviceNode); 00551 00552 KeSetEvent( &parentNode->EnumerationMutex, 0, FALSE ); 00553 00554 if (NT_SUCCESS(status) && !IopDoesDevNodeHaveProblem(deviceNode)) { 00555 PIDBGMSG( PIDBG_EVENTS, 00556 ("IopDeviceActionWorker: START_REQUEST - calling IopNewDevice\n")); 00557 00558 IopNewDevice(deviceObject); 00559 } 00560 00561 IopReleaseDeviceTreeLock(); 00562 00563 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00564 } else { 00565 00566 PDEVICE_NODE RootNode, parentNode; 00567 00568 // 00569 // Acquire the tree lock so no new removals get processed. 00570 // Note that devnodes already locked might still get removed while we hold the tree lock. 00571 // 00572 00573 ExAcquireResourceShared(&IopDeviceTreeLock, TRUE); 00574 00575 // 00576 // Reenumerate the target devnode. 00577 // 00578 00579 deviceNode = RootNode = request->DeviceObject->DeviceObjectExtension->DeviceNode; 00580 while(1) { 00581 00582 // 00583 // Validate that the devnode is not already removed. 00584 // 00585 00586 KeEnterCriticalRegion(); 00587 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 00588 00589 parentNode = deviceNode->Parent; 00590 if (parentNode) { 00591 ObReferenceObject(parentNode->PhysicalDeviceObject); 00592 } 00593 ObReferenceObject(deviceNode->PhysicalDeviceObject); 00594 00595 ExReleaseResource(&PpRegistryDeviceResource); 00596 KeLeaveCriticalRegion(); 00597 00598 if (parentNode) { 00599 00600 PDEVICE_NODE tempNode; 00601 00602 IopAcquireEnumerationLock(parentNode); 00603 tempNode = deviceNode->Parent; 00604 IopReleaseEnumerationLock(parentNode); 00605 if (!tempNode) { 00606 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00607 } 00608 parentNode = tempNode; 00609 } 00610 00611 if (!parentNode && deviceNode != IopRootDeviceNode) { 00612 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00613 break; 00614 } 00615 00616 // 00617 // Make sure that the devnode is ready for enumeration. 00618 // 00619 00620 if (!IopDoesDevNodeHaveProblem(deviceNode) && 00621 (deviceNode->Flags & (DNF_ENUMERATED | DNF_STARTED)) == (DNF_ENUMERATED | DNF_STARTED)) { 00622 00623 // 00624 // Enumerate this object 00625 // 00626 00627 status = IopBusCheck( deviceNode->PhysicalDeviceObject, 00628 PnPBootDriversInitialized, // LoadDriver 00629 (BOOLEAN)(request->CompletionEvent != NULL ? FALSE : PnpAsyncOk)); 00630 if (status == STATUS_PNP_RESTART_ENUMERATION) { 00631 00632 if (parentNode) { 00633 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00634 } 00635 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00636 ExReleaseResource(&IopDeviceTreeLock); 00637 PpSynchronizeDeviceEventQueue(); 00638 ExAcquireResourceShared(&IopDeviceTreeLock, TRUE); 00639 deviceNode = RootNode; 00640 continue; 00641 } 00642 } 00643 00644 // 00645 // Process the whole subtree unless specified otherwise. 00646 // 00647 00648 if (request->RequestType != ReenumerateDeviceOnly) { 00649 00650 if (deviceNode->Child) { 00651 00652 PDEVICE_NODE child = deviceNode->Child; 00653 00654 if (parentNode) { 00655 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00656 } 00657 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00658 deviceNode = child; 00659 00660 } else { 00661 00662 while (deviceNode != RootNode) { 00663 00664 if (deviceNode->Sibling) { 00665 00666 PDEVICE_NODE sibling = deviceNode->Sibling; 00667 00668 if (parentNode) { 00669 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00670 } 00671 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00672 deviceNode = sibling; 00673 break; 00674 00675 } else { 00676 00677 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00678 deviceNode = parentNode; 00679 parentNode = deviceNode->Parent; 00680 if (parentNode) { 00681 ObReferenceObject(parentNode->PhysicalDeviceObject); 00682 } 00683 } 00684 } 00685 } 00686 } 00687 00688 // 00689 // We are done if we are back where we started. 00690 // 00691 00692 if (deviceNode == RootNode) { 00693 00694 if (parentNode) { 00695 ObDereferenceObject(parentNode->PhysicalDeviceObject); 00696 } 00697 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 00698 break; 00699 } 00700 } 00701 00702 // 00703 // Unlock the tree so removals can proceed. 00704 // 00705 00706 ExReleaseResource(&IopDeviceTreeLock); 00707 status = STATUS_SUCCESS; 00708 } 00709 00710 Clean0: 00711 // 00712 // Done with this enumeration request 00713 // 00714 00715 if (request->CompletionStatus) { 00716 *request->CompletionStatus = status; 00717 } 00718 00719 if (request->CompletionEvent) { 00720 KeSetEvent(request->CompletionEvent, 0, FALSE); 00721 } 00722 ObDereferenceObject(request->DeviceObject); 00723 ExFreePool(request); 00724 } 00725 } 00726 00727 NTSTATUS 00728 IopBusCheck( 00729 IN PDEVICE_OBJECT DeviceObject, 00730 IN BOOLEAN LoadDriver, 00731 IN BOOLEAN AsyncOk 00732 ) 00733 00734 /*++ 00735 00736 Routine Description: 00737 00738 This routine performs bus check operation on the specified device/bus. 00739 00740 Arguments: 00741 00742 DeviceObject - Supplies a pointer to a device object which will be enumerated. 00743 00744 LoadDriver - Supplies a BOOLEAN value to indicate should a driver be loaded 00745 to complete a enumeration. If false, the enumeration will stop 00746 once the device's controlling service is not loaded yet. This is 00747 mainly for boot device driver initialization. 00748 00749 ParentLockOwned - Specifies if caller already owns the device's parent's lock. 00750 00751 AsyncOk - Specifies can QueryDeviceRelation be done at Async way. 00752 00753 Return Value: 00754 00755 None. 00756 00757 --*/ 00758 00759 { 00760 BOOLEAN newDevice; 00761 PDEVICE_NODE deviceNode, parent = NULL; 00762 NTSTATUS status; 00763 START_CONTEXT startContext; 00764 00765 PAGED_CODE(); 00766 00767 // 00768 // First get a reference to the PDO to make sure it won't go away. 00769 // 00770 00771 ObReferenceObject(DeviceObject); 00772 deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode; 00773 00774 // 00775 // Enumerate the specified device node. 00776 // If any new device node is found, its controlling driver is loaded and 00777 // its AddDevice entry is called. 00778 // 00779 00780 startContext.LoadDriver = LoadDriver; 00781 startContext.NewDevice = FALSE; 00782 startContext.AddContext.GroupsToStart = NO_MORE_GROUP; 00783 startContext.AddContext.GroupToStartNext = NO_MORE_GROUP; 00784 startContext.AddContext.DriverStartType = SERVICE_DEMAND_START; 00785 00786 status = IopEnumerateDevice( deviceNode->PhysicalDeviceObject, 00787 &startContext, 00788 AsyncOk); 00789 00790 if (status != STATUS_PNP_RESTART_ENUMERATION) { 00791 00792 do { 00793 00794 startContext.NewDevice = FALSE; 00795 00796 // 00797 // Process the whole device tree to assign resources to those devices who 00798 // have been successfully added to their drivers. 00799 // 00800 00801 newDevice = IopProcessAssignResources(deviceNode, FALSE, TRUE); 00802 00803 // 00804 // Process the device subtree to start those devices who have been allocated 00805 // resources and waiting to be started. 00806 // Note, the IopProcessStartDevices routine may enumerate new devices. 00807 // 00808 00809 IopProcessStartDevices(deviceNode, &startContext); 00810 newDevice |= startContext.NewDevice; 00811 00812 } while (newDevice); 00813 } 00814 00815 ObDereferenceObject(DeviceObject); 00816 00817 return status; 00818 } 00819 00820 VOID 00821 IopProcessStartDevices( 00822 IN PDEVICE_NODE DeviceNode, 00823 IN PSTART_CONTEXT StartContext 00824 ) 00825 00826 /*++ 00827 00828 Routine Description: 00829 00830 This function is used by Pnp manager to start the devices which have been 00831 allocated resources and waiting to be started. 00832 00833 Parameters: 00834 00835 DeviceNode - Specifies the device node whose subtree is to be checked for StartDevice. 00836 00837 StartContext - specifies if new driver should be loaded to complete the enumeration. 00838 00839 Return Value: 00840 00841 NONE. 00842 00843 --*/ 00844 { 00845 NTSTATUS status; 00846 PDEVICE_NODE deviceNode, nextDeviceNode; 00847 00848 PAGED_CODE(); 00849 00850 // 00851 // Parse the device node subtree to determine which devices need to be started 00852 // 00853 00854 ExAcquireResourceShared(&IopDeviceTreeLock, TRUE); 00855 if (DeviceNode->LockCount == 0) { 00856 00857 KeWaitForSingleObject( &DeviceNode->EnumerationMutex, 00858 Executive, 00859 KernelMode, 00860 FALSE, 00861 NULL ); 00862 00863 deviceNode = DeviceNode->Child; 00864 while (deviceNode) { 00865 nextDeviceNode = deviceNode->Sibling; 00866 status = IopProcessStartDevicesWorker(deviceNode, StartContext); 00867 00868 if (status == STATUS_PNP_RESTART_ENUMERATION) { 00869 00870 IopReleaseEnumerationLock(DeviceNode); 00871 00872 PpSynchronizeDeviceEventQueue(); 00873 00874 ExAcquireResourceShared(&IopDeviceTreeLock, TRUE); 00875 if (DeviceNode->LockCount == 0) { 00876 00877 KeWaitForSingleObject( &DeviceNode->EnumerationMutex, 00878 Executive, 00879 KernelMode, 00880 FALSE, 00881 NULL ); 00882 00883 00884 if (!(DeviceNode->Flags & DNF_STARTED)) { 00885 break; 00886 } 00887 00888 deviceNode = DeviceNode->Child; 00889 00890 continue; 00891 00892 } else { 00893 00894 ExReleaseResource(&IopDeviceTreeLock); 00895 return; 00896 00897 } 00898 } 00899 00900 deviceNode = nextDeviceNode; 00901 } 00902 00903 KeSetEvent( &DeviceNode->EnumerationMutex, 00904 0, 00905 FALSE ); 00906 } 00907 00908 ExReleaseResource(&IopDeviceTreeLock); 00909 } 00910 00911 NTSTATUS 00912 IopProcessStartDevicesWorker( 00913 IN PDEVICE_NODE DeviceNode, 00914 OUT PVOID Context 00915 ) 00916 00917 /*++ 00918 00919 Routine Description: 00920 00921 This function is used by Pnp manager to start the devices which have been allocated 00922 resources and waiting to be started. 00923 00924 Parameters: 00925 00926 DeviceNode - Specifies the device node whose subtree is to be checked for StartDevice. 00927 00928 Context - specifies a pointer to START_CONTEXT to pass start device info. 00929 00930 Return Value: 00931 00932 TRUE. 00933 00934 --*/ 00935 { 00936 NTSTATUS status = STATUS_SUCCESS; 00937 00938 PAGED_CODE(); 00939 00940 if ( (DeviceNode->Flags & DNF_NEED_QUERY_IDS) || // Reported devices are Started but not enumerated 00941 ((DeviceNode->Flags & DNF_ADDED) && 00942 !(DeviceNode->Flags & DNF_START_PHASE) && 00943 (DeviceNode->Flags & DNF_HAS_RESOURCE)) ) { 00944 00945 // 00946 // If device has been added and resources acquired, we will start it by 00947 // sending StartDevice irp and enumerate the device. 00948 // 00949 00950 status = IopStartAndEnumerateDevice(DeviceNode, (PSTART_CONTEXT)Context); 00951 00952 } else { 00953 00954 // 00955 // Acquire enumeration mutex to make sure its children won't change by 00956 // someone else. Note, the current device node is protected by its parent's 00957 // Enumeration mutex and it won't disappear either. 00958 // 00959 00960 ExAcquireResourceShared(&IopDeviceTreeLock, TRUE); 00961 00962 if (DeviceNode->LockCount == 0) { 00963 00964 KeWaitForSingleObject( &DeviceNode->EnumerationMutex, 00965 Executive, 00966 KernelMode, 00967 FALSE, 00968 NULL ); 00969 00970 00971 // 00972 // Recursively mark all of our children deleted. 00973 // 00974 00975 IopForAllChildDeviceNodes(DeviceNode, IopProcessStartDevicesWorker, Context); 00976 00977 // 00978 // Release the enumeration mutex of the device node. 00979 // 00980 00981 KeSetEvent( &DeviceNode->EnumerationMutex, 00982 0, 00983 FALSE ); 00984 00985 } 00986 00987 ExReleaseResource(&IopDeviceTreeLock); 00988 } 00989 00990 return status; 00991 } 00992 00993 NTSTATUS 00994 IopStartAndEnumerateDevice( 00995 IN PDEVICE_NODE DeviceNode, 00996 IN PSTART_CONTEXT StartContext 00997 ) 00998 00999 /*++ 01000 01001 Routine Description: 01002 01003 This routine starts the specified device and enumerates it. 01004 01005 NOTE: The resources for the device should already been allocated. 01006 01007 Arguments: 01008 01009 DeviceNode - Supplies a pointer to a device node which will be started and 01010 enumerated. 01011 01012 StartContext - Supplies a pointer to START_CONTEXT structure to control 01013 how the start should be handled. 01014 01015 Return Value: 01016 01017 NTSTATUS code. 01018 01019 --*/ 01020 01021 { 01022 NTSTATUS status; 01023 UNICODE_STRING unicodeName; 01024 PDEVICE_OBJECT deviceObject; 01025 HANDLE handle; 01026 01027 PAGED_CODE(); 01028 01029 // 01030 // If no driver is loaded or add device failed, don't start it. 01031 // 01032 01033 ASSERT((DeviceNode->Flags & DNF_ADDED) && 01034 (DeviceNode->Flags & (DNF_HAS_RESOURCE | DNF_NO_RESOURCE_REQUIRED)) && 01035 (!(DeviceNode->Flags & DNF_START_PHASE) || (DeviceNode->Flags & DNF_NEED_QUERY_IDS)) 01036 ); 01037 01038 deviceObject = DeviceNode->PhysicalDeviceObject; 01039 01040 // 01041 // First start the device, if it hasn't 01042 // 01043 01044 if (!(DeviceNode->Flags & DNF_STARTED)) { 01045 01046 IopStartDevice(deviceObject); 01047 01048 // 01049 // ADRIAO BUGBUG 11/11/98 - 01050 // Everything in this if clause expects the start call to 01051 // returns synchronously. When AsyncOk == TRUE functionality is fixed, 01052 // code in here should be moved into IopStartDevice. 01053 // 01054 if (DeviceNode->Flags & DNF_STARTED) { 01055 01056 IopDeviceNodeCapabilitiesToRegistry(DeviceNode); 01057 IopQueryDeviceState(deviceObject); 01058 } 01059 } 01060 01061 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS) { 01062 01063 PWCHAR compatibleIds, hwIds; 01064 ULONG hwIdLength, compatibleIdLength; 01065 01066 // 01067 // If the DNF_NEED_QUERY_IDS is set, the device is a reported device. 01068 // It should already be started. We need to enumerate its children and ask 01069 // the HardwareId and the Compatible ids of the detected device. 01070 // 01071 01072 DeviceNode->Flags &= ~DNF_NEED_QUERY_IDS; 01073 status = IopDeviceObjectToDeviceInstance (deviceObject, 01074 &handle, 01075 KEY_READ 01076 ); 01077 if (NT_SUCCESS(status)) { 01078 status = IopQueryCompatibleIds(deviceObject, 01079 BusQueryHardwareIDs, 01080 &hwIds, 01081 &hwIdLength); 01082 01083 if (!NT_SUCCESS(status)) { 01084 hwIds = NULL; 01085 } 01086 01087 status = IopQueryCompatibleIds(deviceObject, 01088 BusQueryCompatibleIDs, 01089 &compatibleIds, 01090 &compatibleIdLength); 01091 if (!NT_SUCCESS(status)) { 01092 compatibleIds = NULL; 01093 } 01094 01095 if (hwIds || compatibleIds) { 01096 KeEnterCriticalRegion(); 01097 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 01098 01099 if (hwIds) { 01100 01101 if (!IopFixupIds(hwIds, hwIdLength)) { 01102 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01103 PNP_ERR_BOGUS_ID, 01104 (ULONG_PTR)deviceObject, 01105 (ULONG_PTR)hwIds, 01106 3); 01107 } 01108 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_HARDWAREID); 01109 ZwSetValueKey(handle, 01110 &unicodeName, 01111 TITLE_INDEX_VALUE, 01112 REG_MULTI_SZ, 01113 hwIds, 01114 hwIdLength 01115 ); 01116 ExFreePool(hwIds); 01117 } 01118 01119 // 01120 // create CompatibleId value name. It is a MULTI_SZ, 01121 // 01122 01123 if (compatibleIds) { 01124 01125 if (!IopFixupIds(compatibleIds, compatibleIdLength)) { 01126 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01127 PNP_ERR_BOGUS_ID, 01128 (ULONG_PTR)deviceObject, 01129 (ULONG_PTR)compatibleIds, 01130 4); 01131 } 01132 01133 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_COMPATIBLEIDS); 01134 ZwSetValueKey(handle, 01135 &unicodeName, 01136 TITLE_INDEX_VALUE, 01137 REG_MULTI_SZ, 01138 compatibleIds, 01139 compatibleIdLength 01140 ); 01141 ExFreePool(compatibleIds); 01142 } 01143 01144 ExReleaseResource(&PpRegistryDeviceResource); 01145 KeLeaveCriticalRegion(); 01146 } 01147 ZwClose(handle); 01148 } 01149 } 01150 01151 if ((DeviceNode->Flags & DNF_STARTED) && 01152 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) { 01153 01154 status = IopEnumerateDevice(deviceObject, StartContext, PnpAsyncOk); 01155 } else { 01156 status = STATUS_SUCCESS; 01157 } 01158 01159 return status; 01160 } 01161 01162 NTSTATUS 01163 IopEnumerateDevice( 01164 IN PDEVICE_OBJECT DeviceObject, 01165 IN PSTART_CONTEXT StartContext, 01166 IN BOOLEAN AsyncOk 01167 ) 01168 01169 /*++ 01170 01171 Routine Description: 01172 01173 This function assumes that the specified physical device object is 01174 a bus and will enumerate all of the children PDOs on the bus. 01175 01176 Arguments: 01177 01178 DeviceObject - Supplies a pointer to the physical device object to be 01179 enumerated. 01180 01181 StartContext - supplies a pointer to the START_CONTEXT to control how to 01182 add/start new devices. 01183 01184 AsyncOk - Specifies can QueryDeviceRelation be done at Async way. 01185 01186 Return Value: 01187 01188 NTSTATUS code. 01189 01190 --*/ 01191 01192 { 01193 NTSTATUS status; 01194 PDEVICE_NODE deviceNode; 01195 PDEVICE_NODE childDeviceNode, nextChildDeviceNode; 01196 PDEVICE_OBJECT childDeviceObject; 01197 PDEVICE_RELATIONS deviceRelations; 01198 ULONG i; 01199 BOOLEAN childRemoved, newChildPostponed; 01200 01201 PAGED_CODE(); 01202 01203 // 01204 // First get a reference to the PDO to make sure it won't go away. 01205 // 01206 01207 ObReferenceObject(DeviceObject); 01208 01209 deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode; 01210 01211 if (deviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) { 01212 01213 // 01214 // This means this device was just started and needed enumeration. 01215 // So, we will report the device arrival. 01216 // 01217 01218 deviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; 01219 // 01220 // The device has been started, attempt to enumerate the device. 01221 // 01222 01223 PpSetPlugPlayEvent( &GUID_DEVICE_ARRIVAL, 01224 deviceNode->PhysicalDeviceObject); 01225 01226 IOP_DIAG_THROW_CHAFF_AT_STARTED_PDO_STACK(DeviceObject); 01227 #if DBG 01228 { 01229 01230 IO_STACK_LOCATION irpSp; 01231 ULONG dummy; 01232 01233 // 01234 // Initialize the stack location to pass to IopSynchronousCall() 01235 // 01236 01237 RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION)); 01238 01239 // 01240 // Set the function codes. 01241 // 01242 01243 irpSp.MajorFunction = IRP_MJ_PNP; 01244 irpSp.MinorFunction = 0xff; 01245 01246 // 01247 // Make the call and return. 01248 // 01249 01250 status = IopSynchronousCall(DeviceObject, &irpSp, (PVOID)&dummy); 01251 if (NT_SUCCESS(status) || dummy != 0) { 01252 if (deviceNode->ServiceName.Buffer) { 01253 DbgPrint("*** BugBug : Driver %wZ returned status = %lx and Information = %lx\n", 01254 &deviceNode->ServiceName, status, dummy); 01255 DbgPrint(" for IRP_MN_BOGUS. "); 01256 ASSERT(0); 01257 } else { 01258 DbgPrint("*** BugBug : Driver returned status = %lx and Information = %lx\n", status, dummy); 01259 DbgPrint(" for IRP_MN_BOGUS. "); 01260 ASSERT(0); 01261 } 01262 } 01263 } 01264 01265 #endif 01266 } 01267 01268 // 01269 // Make sure we don't step on another enumerator's toes 01270 // 01271 01272 IopAcquireEnumerationLock(deviceNode); 01273 01274 if ((deviceNode->Flags & (DNF_STARTED | DNF_REMOVE_PENDING_CLOSES)) != DNF_STARTED) { 01275 status = STATUS_UNSUCCESSFUL; 01276 } else if (deviceNode->Flags & DNF_ENUMERATION_REQUEST_PENDING) { 01277 if (!(deviceNode->Flags & DNF_BEING_ENUMERATED)) { 01278 01279 // 01280 // The enumeration lock of the device must be acquired already 01281 // before performing following instructions. 01282 // 01283 01284 deviceRelations = deviceNode->OverUsed1.PendingDeviceRelations; 01285 deviceNode->OverUsed1.PendingDeviceRelations = NULL; 01286 deviceNode->Flags &= ~DNF_ENUMERATION_REQUEST_PENDING; 01287 status = STATUS_SUCCESS; 01288 } else { 01289 status = STATUS_UNSUCCESSFUL; 01290 } 01291 } else { 01292 status = IopQueryDeviceRelations(BusRelations, DeviceObject, AsyncOk, &deviceRelations); 01293 } 01294 if (!NT_SUCCESS(status) || (status == STATUS_PENDING) || !deviceRelations) { 01295 status = STATUS_SUCCESS; 01296 goto exit; 01297 } 01298 01299 // 01300 // Walk all the child device nodes and mark them as not present 01301 // 01302 01303 childDeviceNode = deviceNode->Child; 01304 while (childDeviceNode) { 01305 childDeviceNode->Flags &= ~DNF_ENUMERATED; 01306 childDeviceNode = childDeviceNode->Sibling; 01307 } 01308 01309 // 01310 // Check all the PDOs returned see if any new one or any one disappeared. 01311 // 01312 01313 for (i = 0; i < deviceRelations->Count; i++) { 01314 01315 childDeviceObject = deviceRelations->Objects[i]; 01316 01317 ASSERT_INITED(childDeviceObject); 01318 01319 if (childDeviceObject->DeviceObjectExtension->ExtensionFlags & DOE_DELETE_PENDING) { 01320 01321 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01322 PNP_ERR_PDO_ENUMERATED_AFTER_DELETION, 01323 (ULONG_PTR)childDeviceObject, 01324 0, 01325 0); 01326 } 01327 01328 // 01329 // We've found another physical device, see if there is 01330 // already a devnode for it. 01331 // 01332 01333 childDeviceNode = (PDEVICE_NODE)childDeviceObject->DeviceObjectExtension->DeviceNode; 01334 if (childDeviceNode == NULL) { 01335 01336 // 01337 // Device node doesn't exist, create one. 01338 // 01339 01340 childDeviceNode = IopAllocateDeviceNode(childDeviceObject); 01341 01342 if (childDeviceNode != NULL) { 01343 01344 // 01345 // We've found or created a devnode for the PDO that the 01346 // bus driver just enumerated. 01347 // 01348 01349 childDeviceNode->Flags |= DNF_ENUMERATED; 01350 01351 // 01352 // Mark the device object a bus enumerated device 01353 // BUGBUG - should be an ASSERT. This should be set by bus drivers. 01354 // 01355 01356 childDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; 01357 01358 // 01359 // Put this new device node at the head of the parent's list 01360 // of children. 01361 // 01362 01363 IopInsertTreeDeviceNode ( 01364 deviceNode, 01365 childDeviceNode 01366 ); 01367 01368 } else { 01369 01370 // 01371 // Had a problem creating a devnode. Pretend we've never 01372 // seen it. 01373 // 01374 KdPrint(("IopEnumerateDevice: Failed to allocate device node space\n")); 01375 ObDereferenceObject(childDeviceObject); 01376 } 01377 } else { 01378 01379 // 01380 // The device is alreay enumerated. Remark it and release the 01381 // device object reference. 01382 // 01383 childDeviceNode->Flags |= DNF_ENUMERATED; 01384 01385 if (childDeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED) { 01386 01387 // 01388 // A dock that was listed as departing in an eject relation 01389 // didn't actually leave. Remove it from the profile transition 01390 // list... 01391 // 01392 IopHardwareProfileCancelRemovedDock(childDeviceNode); 01393 } 01394 01395 ASSERT(!(childDeviceNode->Flags & DNF_DEVICE_GONE)); 01396 01397 ObDereferenceObject(childDeviceObject); 01398 } 01399 } 01400 01401 ExFreePool(deviceRelations); 01402 01403 // 01404 // If we get here, the enumeration was successful. First process 01405 // any missing devnodes. 01406 // 01407 01408 childRemoved = FALSE; 01409 01410 for (childDeviceNode = deviceNode->Child; 01411 childDeviceNode != NULL; 01412 childDeviceNode = nextChildDeviceNode) { 01413 01414 // 01415 // First, we need to remember the 'next child' because the 'child' will be 01416 // removed and we won't be able to find the 'next child.' 01417 // 01418 01419 nextChildDeviceNode = childDeviceNode->Sibling; 01420 01421 if (!(childDeviceNode->Flags & DNF_ENUMERATED)) { 01422 01423 if (!(childDeviceNode->Flags & DNF_DEVICE_GONE)) { 01424 01425 childDeviceNode->Flags |= DNF_DEVICE_GONE; 01426 01427 IopRequestDeviceRemoval( childDeviceNode->PhysicalDeviceObject, 01428 CM_PROB_DEVICE_NOT_THERE); 01429 01430 childRemoved = TRUE; 01431 } 01432 } 01433 } 01434 01435 // 01436 // BUGBUG - currently the root enumerator gets confused if we reenumerate it 01437 // before we process newly reported PDOs. Since it can't possibly create 01438 // the scenario we are trying to fix, we won't bother waiting for the 01439 // removes to complete before processing the new devnodes. 01440 // 01441 01442 if (deviceNode->Parent != NULL && childRemoved) { 01443 01444 status = STATUS_PNP_RESTART_ENUMERATION; 01445 01446 goto exit; 01447 } 01448 01449 // 01450 // Reserve legacy resources for the legacy interface and bus number. 01451 // 01452 01453 if (!IopBootConfigsReserved && deviceNode->InterfaceType != InterfaceTypeUndefined) { 01454 01455 // 01456 // EISA = ISA. 01457 // 01458 01459 if (deviceNode->InterfaceType == Isa) { 01460 01461 IopReserveLegacyBootResources(Eisa, deviceNode->BusNumber); 01462 01463 } 01464 01465 IopReserveLegacyBootResources(deviceNode->InterfaceType, deviceNode->BusNumber); 01466 01467 } 01468 01469 // 01470 // Now process new devnodes that have just appeared. 01471 // 01472 // Walk all of the children to perform driver loading and device addition operations. 01473 // 01474 01475 IopProcessNewChildren(deviceNode, StartContext); 01476 01477 status = STATUS_SUCCESS; 01478 01479 exit: 01480 01481 IopReleaseEnumerationLock(deviceNode); 01482 ObDereferenceObject(DeviceObject); 01483 01484 return status; 01485 } 01486 01487 NTSTATUS 01488 IopProcessNewChildren( 01489 IN PDEVICE_NODE DeviceNode, 01490 IN PSTART_CONTEXT StartContext 01491 ) 01492 { 01493 NTSTATUS status; 01494 PDEVICE_NODE childDeviceNode; 01495 01496 for (childDeviceNode = DeviceNode->Child; 01497 childDeviceNode != NULL; 01498 childDeviceNode = childDeviceNode->Sibling) { 01499 01500 01501 if (childDeviceNode->Flags & DNF_ENUMERATED) { 01502 01503 // 01504 // Make sure they aren't resurrecting dead PDOs. 01505 // 01506 01507 ASSERT(!(childDeviceNode->Flags & DNF_DEVICE_GONE)); 01508 01509 // 01510 // If the device is not processed ... 01511 // 01512 01513 if (!(childDeviceNode->Flags & DNF_PROCESSED)) { 01514 01515 // 01516 // Setup registry key for the newly enumerated device 01517 // 01518 01519 IopProcessNewDeviceNode(childDeviceNode); 01520 } 01521 01522 if (OK_TO_ADD_DEVICE(childDeviceNode)) { 01523 status = IopCallDriverAddDevice(childDeviceNode, 01524 StartContext->LoadDriver, 01525 &StartContext->AddContext); 01526 01527 if (NT_SUCCESS(status)) { 01528 StartContext->NewDevice = TRUE; 01529 } 01530 } 01531 } 01532 } 01533 01534 return STATUS_SUCCESS; 01535 } 01536 01537 NTSTATUS 01538 IopProcessNewDeviceNode( 01539 IN OUT PDEVICE_NODE DeviceNode 01540 ) 01541 01542 /*++ 01543 01544 Routine Description: 01545 01546 This function creates a device instance key for the specified device. 01547 If LoadDriver is true and the device driver for the device is installed, 01548 this routine will load the driver to start enumerating its children. 01549 01550 Arguments: 01551 01552 DeviceNode - Supplies a pointer to the device node to be processed. 01553 01554 Return Value: 01555 01556 NTSTATUS code. 01557 01558 --*/ 01559 01560 { 01561 NTSTATUS status; 01562 PWCHAR deviceId, busId, uniqueId, compatibleIds, id, hwIds, deviceText, globallyUniqueId; 01563 HANDLE handle, enumHandle, busIdHandle, deviceIdHandle; 01564 HANDLE uniqueIdHandle, logConfHandle; 01565 UNICODE_STRING unicodeName, unicodeString, unicodeDeviceInstance; 01566 ULONG disposition, tmpValue, length, cmLength, ioLength, hwIdLength, compatibleIdLength; 01567 PCM_RESOURCE_LIST cmResource; 01568 PIO_RESOURCE_REQUIREMENTS_LIST ioResource; 01569 PKEY_VALUE_FULL_INFORMATION keyValueInformation; 01570 PWCHAR buffer = NULL; 01571 PDEVICE_OBJECT deviceObject; 01572 PDEVICE_NODE deviceNode; 01573 IO_STACK_LOCATION irpSp; 01574 DEVICE_CAPABILITIES capabilities; 01575 PVOID dummy = NULL; 01576 BOOLEAN globallyUnique = FALSE; 01577 PWCHAR location = NULL, description = NULL; 01578 PKEY_VALUE_PARTIAL_INFORMATION keyValue; 01579 UCHAR CLSIDBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 128]; 01580 01581 BOOLEAN processCriticalDevice = FALSE; 01582 BOOLEAN isRemoteBootCard = FALSE; 01583 BOOLEAN configuredBySetup; 01584 PWCHAR wp; 01585 GUID busTypeGuid; 01586 01587 PAGED_CODE(); 01588 01589 deviceObject = DeviceNode->PhysicalDeviceObject; 01590 01591 // 01592 // First open HKLM\System\CCS\Enum key. 01593 // 01594 01595 status = IopOpenRegistryKeyEx( &enumHandle, 01596 NULL, 01597 &CmRegistryMachineSystemCurrentControlSetEnumName, 01598 KEY_ALL_ACCESS 01599 ); 01600 if (!NT_SUCCESS(status)) { 01601 KdPrint(("IopProcessNewDeviceNode: Unable to open HKLM\\SYSTEM\\CCS\\ENUM\n")); 01602 return status; 01603 } 01604 01605 // 01606 // First, get the device id and this will be the device key name 01607 // 01608 01609 status = IopQueryDeviceId(deviceObject, &id); 01610 01611 if (!NT_SUCCESS(status) || id == NULL) { 01612 ZwClose(enumHandle); 01613 return status; 01614 } 01615 01616 // 01617 // Fix up the id if necessary 01618 // 01619 if (!IopFixupDeviceId(id)) { 01620 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01621 PNP_ERR_BOGUS_ID, 01622 (ULONG_PTR)deviceObject, 01623 (ULONG_PTR)id, 01624 1); 01625 01626 01627 } 01628 01629 // 01630 // Extract bus id out of the returned id 01631 // 01632 01633 for (wp = id; *wp != UNICODE_NULL; wp++) { 01634 if (*wp == OBJ_NAME_PATH_SEPARATOR) { 01635 deviceId = wp + 1; 01636 busId = id; 01637 break; 01638 } 01639 } 01640 01641 if (*wp != OBJ_NAME_PATH_SEPARATOR) { 01642 ZwClose(enumHandle); 01643 ExFreePool(id); 01644 KdPrint(("IopProcessNewDevice: Invalid device id return by driver (not in bus\\device format)\n")); 01645 return STATUS_UNSUCCESSFUL; 01646 } 01647 01648 *wp = UNICODE_NULL; 01649 01650 KeEnterCriticalRegion(); 01651 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 01652 01653 // 01654 // Open/Create enumerator key under HKLM\CCS\System\Enum 01655 // 01656 01657 RtlInitUnicodeString(&unicodeName, busId); 01658 01659 status = IopCreateRegistryKeyEx( &busIdHandle, 01660 enumHandle, 01661 &unicodeName, 01662 KEY_ALL_ACCESS, 01663 REG_OPTION_NON_VOLATILE, 01664 NULL 01665 ); 01666 01667 if (!NT_SUCCESS(status)) { 01668 ExFreePool(id); 01669 ZwClose(enumHandle); 01670 goto exit; 01671 } 01672 01673 // 01674 // Open/create this registry path under HKLM\CCS\System\Enum<Enumerator> 01675 // 01676 01677 RtlInitUnicodeString(&unicodeName, deviceId); 01678 status = IopCreateRegistryKeyEx( &deviceIdHandle, 01679 busIdHandle, 01680 &unicodeName, 01681 KEY_ALL_ACCESS, 01682 REG_OPTION_NON_VOLATILE, 01683 NULL 01684 ); 01685 01686 ZwClose(busIdHandle); 01687 if (!NT_SUCCESS(status)) { 01688 ExFreePool(id); 01689 ZwClose(enumHandle); 01690 goto exit; 01691 } 01692 01693 ExReleaseResource(&PpRegistryDeviceResource); 01694 KeLeaveCriticalRegion(); 01695 01696 // 01697 // Query the device's capabilities 01698 // we will add this stuff to registry once we've processed it a bit 01699 // 01700 01701 status = IopQueryDeviceCapabilities(DeviceNode, &capabilities); 01702 01703 if (capabilities.NoDisplayInUI) { 01704 01705 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; 01706 } 01707 01708 // 01709 // From the query capabilities call, determine if this a globally unique ID? 01710 // 01711 01712 if (NT_SUCCESS(status) && (capabilities.UniqueID)) { 01713 globallyUnique = TRUE; 01714 } 01715 01716 // 01717 // Record, is this a dock? 01718 // 01719 DeviceNode->DockInfo.DockStatus = 01720 capabilities.DockDevice ? DOCK_QUIESCENT : DOCK_NOTDOCKDEVICE; 01721 01722 // 01723 // Initialize the stack location to pass to IopSynchronousCall() 01724 // 01725 01726 RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION)); 01727 01728 // 01729 // Query the device's description. 01730 // 01731 01732 irpSp.MajorFunction = IRP_MJ_PNP; 01733 irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT; 01734 irpSp.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; 01735 irpSp.Parameters.QueryDeviceText.LocaleId = PsDefaultSystemLocaleId; 01736 status = IopSynchronousCall(deviceObject, &irpSp, &description); 01737 01738 if (!NT_SUCCESS(status)) { 01739 description = NULL; 01740 } 01741 01742 // 01743 // Initialize the stack location to pass to IopSynchronousCall() 01744 // 01745 01746 RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION)); 01747 01748 // 01749 // Query the device's location information. 01750 // 01751 01752 irpSp.MajorFunction = IRP_MJ_PNP; 01753 irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT; 01754 irpSp.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; 01755 irpSp.Parameters.QueryDeviceText.LocaleId = PsDefaultSystemLocaleId; 01756 status = IopSynchronousCall(deviceObject, &irpSp, &location); 01757 01758 if (!NT_SUCCESS(status)) { 01759 location = NULL; 01760 } 01761 01762 // 01763 // Query the unique id for the device 01764 // 01765 01766 IopQueryUniqueId(deviceObject, &uniqueId); 01767 01768 deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode; 01769 01770 if (!globallyUnique && deviceNode->Parent != IopRootDeviceNode) { 01771 globallyUniqueId = NULL; 01772 01773 status = IopMakeGloballyUniqueId(deviceObject, uniqueId, &globallyUniqueId); 01774 01775 if (uniqueId != NULL) { 01776 ExFreePool(uniqueId); 01777 } 01778 01779 uniqueId = globallyUniqueId; 01780 01781 } else { 01782 01783 status = STATUS_SUCCESS; 01784 } 01785 01786 if (!NT_SUCCESS(status) || uniqueId == NULL) { 01787 if (description) { 01788 ExFreePool(description); 01789 } 01790 if (location) { 01791 ExFreePool(location); 01792 } 01793 ZwClose(deviceIdHandle); 01794 ZwClose(enumHandle); 01795 ExFreePool(id); 01796 return status; 01797 } 01798 01799 KeEnterCriticalRegion(); 01800 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 01801 01802 RetryDuplicateId: 01803 01804 // 01805 // Fixup the unique instance id if necessary 01806 // 01807 if (!IopFixupDeviceId(uniqueId)) { 01808 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01809 PNP_ERR_BOGUS_ID, 01810 (ULONG_PTR)deviceObject, 01811 (ULONG_PTR)uniqueId, 01812 2); 01813 } 01814 01815 length = (wcslen(busId) + wcslen(deviceId) + wcslen(uniqueId) + 5) * sizeof(WCHAR); 01816 buffer = (PWCHAR)ExAllocatePool(PagedPool, length); 01817 if (!buffer) { 01818 01819 ExReleaseResource(&PpRegistryDeviceResource); 01820 KeLeaveCriticalRegion(); 01821 01822 if (description) { 01823 ExFreePool(description); 01824 } 01825 if (location) { 01826 ExFreePool(location); 01827 } 01828 ZwClose(deviceIdHandle); 01829 ZwClose(enumHandle); 01830 ExFreePool(id); 01831 return STATUS_INSUFFICIENT_RESOURCES; 01832 } 01833 swprintf(buffer, L"%s\\%s\\%s", busId, deviceId, uniqueId); 01834 RtlInitUnicodeString(&unicodeDeviceInstance, buffer); 01835 01836 if (DeviceNode->InstancePath.Buffer != NULL) { 01837 01838 ExFreePool(DeviceNode->InstancePath.Buffer); 01839 RtlInitUnicodeString(&DeviceNode->InstancePath, NULL); 01840 } 01841 01842 IopConcatenateUnicodeStrings(&DeviceNode->InstancePath, &unicodeDeviceInstance, NULL); 01843 01844 // 01845 // Open/create this registry device instance path under 01846 // HKLM\System\Enum<Enumerator>\deviceId 01847 // 01848 01849 RtlInitUnicodeString(&unicodeName, uniqueId); 01850 status = IopCreateRegistryKeyEx( &uniqueIdHandle, 01851 deviceIdHandle, 01852 &unicodeName, 01853 KEY_ALL_ACCESS, 01854 REG_OPTION_NON_VOLATILE, 01855 &disposition 01856 ); 01857 01858 if (!NT_SUCCESS(status)) { 01859 ZwClose(enumHandle); 01860 ExFreePool(id); 01861 ZwClose(deviceIdHandle); 01862 ExFreePool(uniqueId); 01863 goto exit; 01864 } 01865 01866 deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING; 01867 01868 DeviceNode->Flags |= DNF_PROCESSED; 01869 01870 // 01871 // Check if the device instance is already reported. If yes fail this request. 01872 // 01873 01874 if (disposition != REG_CREATED_NEW_KEY) { 01875 01876 PDEVICE_OBJECT dupCheckDeviceObject; 01877 01878 // 01879 // Retrieve the device node associated with this device instance name (if 01880 // there is one). If it's different from the device node we're currently 01881 // working with, then we have a duplicate, and we want to remove it. 01882 // 01883 01884 dupCheckDeviceObject = IopDeviceObjectFromDeviceInstance(uniqueIdHandle, NULL); 01885 01886 if (dupCheckDeviceObject) { 01887 01888 // 01889 // Go ahead and dereference the device object now--we only need the 01890 // value for comparison. 01891 // 01892 01893 ObDereferenceObject(dupCheckDeviceObject); 01894 01895 if (dupCheckDeviceObject != deviceObject) { 01896 01897 if (globallyUnique) { 01898 globallyUnique = FALSE; 01899 01900 IopMakeGloballyUniqueId(deviceObject, uniqueId, &globallyUniqueId); 01901 01902 if (uniqueId != NULL) { 01903 ExFreePool(uniqueId); 01904 } 01905 01906 uniqueId = globallyUniqueId; 01907 01908 ExFreePool(buffer); 01909 buffer = NULL; 01910 ZwClose(uniqueIdHandle); 01911 IopSetDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART); 01912 goto RetryDuplicateId; 01913 } 01914 01915 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01916 PNP_ERR_DUPLICATE_PDO, 01917 (ULONG_PTR)deviceObject, 01918 (ULONG_PTR)dupCheckDeviceObject, 01919 0); 01920 01921 #if 0 01922 ZwClose(enumHandle); 01923 ZwClose(uniqueIdHandle); 01924 01925 if (DeviceNode->InstancePath.Length != 0) { 01926 ExFreePool(DeviceNode->InstancePath.Buffer); 01927 DeviceNode->InstancePath.Length = 0; 01928 DeviceNode->InstancePath.Buffer = NULL; 01929 } 01930 01931 IopRequestDeviceRemoval(deviceObject, CM_PROB_DEVICE_NOT_THERE); 01932 goto exit; 01933 #endif 01934 } 01935 } 01936 } else { 01937 01938 if (description) { 01939 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_DEVDESC); 01940 ZwSetValueKey(uniqueIdHandle, 01941 &unicodeName, 01942 TITLE_INDEX_VALUE, 01943 REG_SZ, 01944 description, 01945 (wcslen(description)+1) * sizeof(WCHAR) 01946 ); 01947 ExFreePool(description); 01948 description = NULL; 01949 } 01950 } 01951 01952 ExFreePool(id); 01953 ZwClose(deviceIdHandle); 01954 ExFreePool(uniqueId); 01955 01956 if (location) { 01957 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_LOCATION_INFORMATION); 01958 ZwSetValueKey(uniqueIdHandle, 01959 &unicodeName, 01960 TITLE_INDEX_VALUE, 01961 REG_SZ, 01962 location, 01963 (wcslen(location)+1) * sizeof(WCHAR) 01964 ); 01965 ExFreePool(location); 01966 location = NULL; 01967 } 01968 01969 // 01970 // now add the capabilities and UI_NUMBER into registry 01971 // 01972 status = IopDeviceCapabilitiesToRegistry(DeviceNode, &capabilities); 01973 01974 #if DBG 01975 ASSERT(status == STATUS_SUCCESS); 01976 #endif 01977 01978 PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF); 01979 status = IopCreateRegistryKeyEx( &logConfHandle, 01980 uniqueIdHandle, 01981 &unicodeName, 01982 KEY_ALL_ACCESS, 01983 REG_OPTION_NON_VOLATILE, 01984 NULL 01985 ); 01986 if (!NT_SUCCESS(status)) { 01987 logConfHandle = NULL; // just to make sure 01988 } 01989 01990 if (disposition == REG_CREATED_NEW_KEY) { // disposition from uniqueId 01991 01992 // 01993 // "new registry key" device installation case 01994 // 01995 // Set flags to control whether device installation needs to 01996 // happen later. This means setting the devnode flag to 01997 // DNF_NOT_CONFIGURED and setting the ConfigFlag ONLY if it's 01998 // raw. 01999 // 02000 02001 if (!IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) { 02002 if (capabilities.RawDeviceOK) { 02003 PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CONFIG_FLAGS); 02004 tmpValue = CONFIGFLAG_FINISH_INSTALL; 02005 ZwSetValueKey(uniqueIdHandle, 02006 &unicodeName, 02007 TITLE_INDEX_VALUE, 02008 REG_DWORD, 02009 &tmpValue, 02010 sizeof(tmpValue) 02011 ); 02012 } else { 02013 IopSetDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED); 02014 } 02015 02016 // 02017 // Process this as a critical device node. This will setup 02018 // the service, if necessary, so that the system can boot far 02019 // enough to get to the config manager 02020 // 02021 02022 processCriticalDevice = TRUE; 02023 } 02024 02025 } else { 02026 02027 UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)]; 02028 PKEY_VALUE_PARTIAL_INFORMATION keyInfo = 02029 (PKEY_VALUE_PARTIAL_INFORMATION) buffer; 02030 02031 ULONG length; 02032 02033 UNICODE_STRING valueName; 02034 02035 NTSTATUS tmpStatus; 02036 02037 if (!IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) { 02038 02039 RtlInitUnicodeString(&valueName, REGSTR_VALUE_CONFIG_FLAGS); 02040 tmpStatus = ZwQueryValueKey(uniqueIdHandle, 02041 &valueName, 02042 KeyValuePartialInformation, 02043 keyInfo, 02044 sizeof(buffer), 02045 &length); 02046 02047 if (NT_SUCCESS(tmpStatus)) { 02048 02049 ULONG configFlags = *(PULONG)keyInfo->Data; 02050 02051 // 02052 // The ConfigFlags value exists in the registry 02053 // If DNF_REINSTALL is set. We mark it as DNF_DELETED such that we will not 02054 // start the device. Later when the reinstallation completes, the 02055 // DNF_RESTART_OK bit will be set and DNF_DELETED will be deleted. 02056 // 02057 02058 if (configFlags & CONFIGFLAG_REINSTALL) { 02059 IopSetDevNodeProblem(DeviceNode, CM_PROB_REINSTALL); 02060 processCriticalDevice = TRUE; // to install critical driver 02061 } else if (configFlags & CONFIGFLAG_FAILEDINSTALL) { 02062 IopSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL); 02063 processCriticalDevice = TRUE; // to install critical driver 02064 } 02065 } else { 02066 // 02067 // The ConfigFlag value does not exist in the registry 02068 // 02069 IopSetDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED); 02070 } 02071 } 02072 02073 RtlInitUnicodeString(&valueName, REGSTR_VALUE_SERVICE); 02074 02075 tmpStatus = ZwQueryValueKey(uniqueIdHandle, 02076 &valueName, 02077 KeyValuePartialInformation, 02078 keyInfo, 02079 sizeof(buffer), 02080 &length); 02081 02082 // 02083 // if there's no service setup then check to see if this should 02084 // be processed as a critical device. 02085 // 02086 02087 if (NT_SUCCESS(tmpStatus) && (keyInfo->DataLength <= sizeof(L'\0'))) { 02088 processCriticalDevice = TRUE; 02089 } else if (tmpStatus == STATUS_OBJECT_NAME_NOT_FOUND) { 02090 processCriticalDevice = TRUE; 02091 } 02092 } 02093 02094 if (capabilities.HardwareDisabled && 02095 !IopIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) && 02096 !IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) { 02097 // 02098 // mark the node as hardware disabled, if no configuration problems 02099 // 02100 IopClearDevNodeProblem(DeviceNode); 02101 IopSetDevNodeProblem(DeviceNode, CM_PROB_HARDWARE_DISABLED); 02102 // 02103 // Issue a PNP REMOVE_DEVICE Irp so when we query resources 02104 // we have those required after boot 02105 // 02106 status = IopRemoveDevice(deviceObject, IRP_MN_REMOVE_DEVICE); 02107 ASSERT(NT_SUCCESS(status)); 02108 02109 } else { 02110 // 02111 // these are the only problems I expect at this point 02112 // 02113 ASSERT(!IopDoesDevNodeHaveProblem(DeviceNode) || 02114 IopIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) || 02115 IopIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL) || 02116 IopIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) || 02117 IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)); 02118 } 02119 02120 // 02121 // Create all the default value entry for the newly created key. 02122 // Configuration = REG_RESOURCE_LIST 02123 // ConfigurationVector = REG_RESOUCE_REQUIREMENTS_LIST 02124 // HardwareID = MULTI_SZ 02125 // CompatibleIDs = MULTI_SZ 02126 // Create "Control" volatile subkey. 02127 // 02128 02129 PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL); 02130 status = IopCreateRegistryKeyEx( &handle, 02131 uniqueIdHandle, 02132 &unicodeName, 02133 KEY_ALL_ACCESS, 02134 REG_OPTION_VOLATILE, 02135 NULL 02136 ); 02137 if (NT_SUCCESS(status)) { 02138 02139 // 02140 // Write DeviceObject reference ... 02141 // 02142 02143 PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DEVICE_REFERENCE); 02144 status = ZwSetValueKey( handle, 02145 &unicodeName, 02146 TITLE_INDEX_VALUE, 02147 REG_DWORD, 02148 (PULONG_PTR)&deviceObject, 02149 sizeof(ULONG_PTR) 02150 ); 02151 ZwClose(handle); 02152 } 02153 02154 if (!NT_SUCCESS(status)) { 02155 ZwClose(enumHandle); 02156 ZwClose(uniqueIdHandle); 02157 if (logConfHandle) { 02158 ZwClose(logConfHandle); 02159 } 02160 goto exit; 02161 } 02162 02163 ZwClose(enumHandle); 02164 02165 // 02166 // Release registry lock before calling device driver 02167 // 02168 02169 ExReleaseResource(&PpRegistryDeviceResource); 02170 KeLeaveCriticalRegion(); 02171 02172 status = IopQueryCompatibleIds( deviceObject, 02173 BusQueryHardwareIDs, 02174 &hwIds, 02175 &hwIdLength); 02176 02177 if (!NT_SUCCESS(status)) { 02178 hwIds = NULL; 02179 } 02180 02181 status = IopQueryCompatibleIds( deviceObject, 02182 BusQueryCompatibleIDs, 02183 &compatibleIds, 02184 &compatibleIdLength); 02185 if (!NT_SUCCESS(status)) { 02186 compatibleIds = NULL; 02187 } 02188 02189 // 02190 // Query the device's basic config vector. This needs to be done before we check if 02191 // this is a remote BOOT card. 02192 // 02193 02194 RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION)); 02195 irpSp.MajorFunction = IRP_MJ_PNP; 02196 irpSp.MinorFunction = IRP_MN_QUERY_RESOURCE_REQUIREMENTS; 02197 status = IopSynchronousCall(deviceObject, &irpSp, &ioResource); 02198 02199 if (!NT_SUCCESS(status)) { 02200 ioResource = NULL; 02201 } 02202 if (ioResource) { 02203 ioLength = ioResource->ListSize; 02204 } 02205 02206 KeEnterCriticalRegion(); 02207 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 02208 02209 // 02210 // Write resource requirements to registry 02211 // 02212 02213 if (logConfHandle) { 02214 PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_BASIC_CONFIG_VECTOR); 02215 if (ioResource) { 02216 ZwSetValueKey(logConfHandle, 02217 &unicodeName, 02218 TITLE_INDEX_VALUE, 02219 REG_RESOURCE_REQUIREMENTS_LIST, 02220 ioResource, 02221 ioLength 02222 ); 02223 DeviceNode->ResourceRequirements = ioResource; 02224 DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED; 02225 } else { 02226 ZwDeleteValueKey(logConfHandle, &unicodeName); 02227 } 02228 } 02229 02230 // 02231 // While we have the hwIds, check if this is the device node 02232 // for the remote boot net card. If IopLoaderBlock is NULL 02233 // then we are not initilizing boot drivers so we don't have 02234 // to check for this. 02235 // 02236 02237 if (IoRemoteBootClient && (IopLoaderBlock != NULL)) { 02238 02239 if (hwIds) { 02240 isRemoteBootCard = IopIsRemoteBootCard( 02241 DeviceNode, 02242 (PLOADER_PARAMETER_BLOCK)IopLoaderBlock, 02243 hwIds); 02244 } 02245 if (!isRemoteBootCard && compatibleIds) { 02246 isRemoteBootCard = IopIsRemoteBootCard( 02247 DeviceNode, 02248 (PLOADER_PARAMETER_BLOCK)IopLoaderBlock, 02249 compatibleIds); 02250 } 02251 } 02252 02253 // 02254 // create HardwareId value name. It is a MULTI_SZ, 02255 // 02256 02257 if (hwIds) { 02258 02259 if (!IopFixupIds(hwIds, hwIdLength)) { 02260 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 02261 PNP_ERR_BOGUS_ID, 02262 (ULONG_PTR)deviceObject, 02263 (ULONG_PTR)hwIds, 02264 3); 02265 } 02266 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_HARDWAREID); 02267 ZwSetValueKey(uniqueIdHandle, 02268 &unicodeName, 02269 TITLE_INDEX_VALUE, 02270 REG_MULTI_SZ, 02271 hwIds, 02272 hwIdLength 02273 ); 02274 ExFreePool(hwIds); 02275 } 02276 02277 // 02278 // create CompatibleId value name. It is a MULTI_SZ, 02279 // 02280 02281 if (compatibleIds) { 02282 02283 if (!IopFixupIds(compatibleIds, compatibleIdLength)) { 02284 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 02285 PNP_ERR_BOGUS_ID, 02286 (ULONG_PTR)deviceObject, 02287 (ULONG_PTR)compatibleIds, 02288 4); 02289 } 02290 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_COMPATIBLEIDS); 02291 ZwSetValueKey(uniqueIdHandle, 02292 &unicodeName, 02293 TITLE_INDEX_VALUE, 02294 REG_MULTI_SZ, 02295 compatibleIds, 02296 compatibleIdLength 02297 ); 02298 ExFreePool(compatibleIds); 02299 } 02300 02301 // 02302 // If this is the devnode for the remote boot card, do 02303 // special setup for it. 02304 // 02305 02306 if (isRemoteBootCard) { 02307 02308 status = IopSetupRemoteBootCard( 02309 (PLOADER_PARAMETER_BLOCK)IopLoaderBlock, 02310 uniqueIdHandle, 02311 &unicodeDeviceInstance); 02312 02313 if (status != STATUS_SUCCESS) { 02314 goto exit; 02315 } 02316 02317 // 02318 // HACK BUGBUG: Need to turn this off, or else the device won't 02319 // be allowed to be opened until the PNP start IRP is done. Unfortunately 02320 // that is exactly what NDIS does in the start IRP handler - adamba 3/31/99 02321 // 02322 02323 deviceObject->DeviceObjectExtension->ExtensionFlags &= ~DOE_START_PENDING; 02324 02325 } 02326 02327 ExReleaseResource(&PpRegistryDeviceResource); 02328 KeLeaveCriticalRegion(); 02329 02330 // 02331 // we've pretty much got the PDO information ready, apart from Child bus information 02332 // get that now, because class-installer may want it 02333 // 02334 status = IopQueryPnpBusInformation( 02335 deviceObject, 02336 &busTypeGuid, 02337 &DeviceNode->ChildInterfaceType, 02338 &DeviceNode->ChildBusNumber 02339 ); 02340 02341 if (NT_SUCCESS(status)) { 02342 02343 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&busTypeGuid); 02344 02345 } else { 02346 02347 DeviceNode->ChildBusTypeIndex = 0xffff; 02348 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; 02349 DeviceNode->ChildBusNumber = 0xfffffff0; 02350 02351 } 02352 02353 // 02354 // we check HardwareDisabled directly in case it's a new device 02355 // 02356 if (processCriticalDevice && !capabilities.HardwareDisabled && 02357 !IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) { 02358 02359 IopProcessCriticalDevice(DeviceNode); 02360 } 02361 02362 // 02363 // Set DNF_DISABLED flag if the device instance is disabled. 02364 // 02365 02366 ASSERT(!IopDoesDevNodeHaveProblem(DeviceNode) || 02367 IopIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) || 02368 IopIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL) || 02369 IopIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) || 02370 IopIsDevNodeProblem(DeviceNode, CM_PROB_PARTIAL_LOG_CONF) || 02371 IopIsDevNodeProblem(DeviceNode, CM_PROB_HARDWARE_DISABLED) || 02372 IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)); 02373 if (!IopIsDevNodeProblem(DeviceNode, CM_PROB_DISABLED) && 02374 !IopIsDevNodeProblem(DeviceNode, CM_PROB_HARDWARE_DISABLED) && 02375 !IopIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) { 02376 02377 IopIsDeviceInstanceEnabled(uniqueIdHandle, &unicodeDeviceInstance, TRUE); 02378 } 02379 02380 // 02381 // This code HAS to be after we have checked for DISABLED device. 02382 // We could end up here from an ENABLE following a DISABLE. 02383 // Query for BOOT config if there is none already present. 02384 // 02385 02386 cmResource = NULL; 02387 if (DeviceNode->BootResources == NULL) { 02388 status = IopQueryDeviceResources( deviceObject, 02389 QUERY_RESOURCE_LIST, 02390 &cmResource, 02391 &cmLength ); 02392 if (!NT_SUCCESS(status)) { 02393 cmResource = NULL; 02394 } 02395 } else { 02396 02397 DebugPrint(1, 02398 ("PNPENUM: %ws already has BOOT config in IopProcessNewDeviceNode!\n", 02399 DeviceNode->InstancePath.Buffer)); 02400 } 02401 02402 KeEnterCriticalRegion(); 02403 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 02404 02405 // 02406 // Write boot resources to registry 02407 // 02408 if (logConfHandle && DeviceNode->BootResources == NULL) { 02409 PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG); 02410 if (cmResource) { 02411 ZwSetValueKey( 02412 logConfHandle, 02413 &unicodeName, 02414 TITLE_INDEX_VALUE, 02415 REG_RESOURCE_LIST, 02416 cmResource, 02417 cmLength 02418 ); 02419 02420 ExReleaseResource(&PpRegistryDeviceResource); 02421 02422 // 02423 // This device consumes BOOT resources. Reserve its boot resources 02424 // 02425 02426 status = (*IopReserveResourcesRoutine)(ArbiterRequestPnpEnumerated, 02427 deviceObject, 02428 cmResource); 02429 02430 ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE); 02431 02432 if (NT_SUCCESS(status)) { 02433 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG; 02434 } 02435 ExFreePool(cmResource); 02436 } else { 02437 ZwDeleteValueKey(logConfHandle, &unicodeName); 02438 } 02439 } 02440 02441 // 02442 // SurpriseRemovalOK bits may have changed due to DNF_HAS_BOOT_CONFIG. 02443 // 02444 status = IopDeviceCapabilitiesToRegistry(DeviceNode,&capabilities); 02445 02446 #if DBG 02447 ASSERT(status == STATUS_SUCCESS); 02448 #endif 02449 02450 // 02451 // Clean up 02452 // 02453 02454 if (logConfHandle) { 02455 ZwClose(logConfHandle); 02456 } 02457 02458 ExReleaseResource(&PpRegistryDeviceResource); 02459 KeLeaveCriticalRegion(); 02460 02461 // 02462 // Create new value entry under ServiceKeyName\Enum to reflect the newly 02463 // added made-up device instance node. 02464 // 02465 02466 status = IopNotifySetupDeviceArrival( deviceObject, 02467 uniqueIdHandle, 02468 TRUE); 02469 02470 configuredBySetup = NT_SUCCESS(status); 02471 02472 status = PpDeviceRegistration( 02473 &unicodeDeviceInstance, 02474 TRUE, 02475 &DeviceNode->ServiceName 02476 ); 02477 02478 if (NT_SUCCESS(status) && (configuredBySetup || isRemoteBootCard) && 02479 IopIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED)) { 02480 02481 IopClearDevNodeProblem(DeviceNode); 02482 } 02483 02484 // 02485 // Add an event so user-mode will attempt to install this device later. 02486 // 02487 PpSetPlugPlayEvent( &GUID_DEVICE_ENUMERATED, 02488 deviceObject); 02489 02490 ZwClose(uniqueIdHandle); 02491 02492 if (buffer) { 02493 ExFreePool(buffer); 02494 } 02495 if (description) { 02496 ExFreePool(description); 02497 } 02498 if (location) { 02499 ExFreePool(location); 02500 } 02501 return STATUS_SUCCESS; 02502 02503 exit: 02504 02505 // 02506 // In case of failure, we don't set the DNF_PROCESSED flags. So the device 02507 // will be processed again later. 02508 // 02509 02510 ExReleaseResource(&PpRegistryDeviceResource); 02511 KeLeaveCriticalRegion(); 02512 if (buffer) { 02513 ExFreePool(buffer); 02514 } 02515 if (description) { 02516 ExFreePool(description); 02517 } 02518 if (location) { 02519 ExFreePool(location); 02520 } 02521 return status; 02522 } 02523 02524 NTSTATUS 02525 IopCallDriverAddDevice( 02526 IN PDEVICE_NODE DeviceNode, 02527 IN BOOLEAN LoadDriver, 02528 IN PADD_CONTEXT Context 02529 ) 02530 02531 /*++ 02532 02533 Routine Description: 02534 02535 This function checks if the driver for the DeviceNode is present and loads 02536 the driver if necessary. 02537 02538 Arguments: 02539 02540 DeviceNode - Supplies a pointer to the device node to be enumerated. 02541 02542 LoadDriver - Supplies a BOOLEAN value to indicate should a driver be loaded 02543 to complete enumeration. 02544 02545 Context - Supplies a pointer to ADD_CONTEXT to control how the device be added. 02546 02547 Return Value: 02548 02549 NTSTATUS code. 02550 02551 --*/ 02552 02553 { 02554 HANDLE enumKey; 02555 HANDLE instanceKey; 02556 HANDLE classKey = NULL; 02557 HANDLE classPropsKey = NULL; 02558 PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL; 02559 RTL_QUERY_REGISTRY_TABLE queryTable[3]; 02560 QUERY_CONTEXT queryContext; 02561 BOOLEAN deviceRaw = FALSE; 02562 BOOLEAN usePdoCharacteristics = TRUE; 02563 NTSTATUS status; 02564 DEVICE_CAPABILITIES capabilities; 02565 ULONG index; 02566 PDEVICE_OBJECT deviceObject; 02567 #ifndef NO_SPECIAL_IRP 02568 PDEVICE_OBJECT fdoDeviceObject, topOfPdoStack, topOfLowerFilterStack; 02569 BOOLEAN deviceObjectHasBeenAttached = FALSE; 02570 #endif 02571 02572 DebugPrint(1, ("IopCallDriverAddDevice: Processing devnode %#08lx\n", 02573 DeviceNode)); 02574 02575 DebugPrint(1, ("IopCallDriverAddDevice: DevNode flags going in = %#08lx\n", 02576 DeviceNode->Flags)); 02577 02578 // 02579 // The device node may have been started at this point. This is because 02580 // some ill-behaved miniport drivers call IopReportedDetectedDevice at 02581 // DriverEntry for the devices which we already know about. 02582 // 02583 02584 if (!OK_TO_ADD_DEVICE(DeviceNode)) { 02585 return STATUS_SUCCESS; 02586 } 02587 02588 ASSERT_INITED(DeviceNode->PhysicalDeviceObject); 02589 02590 DebugPrint(1, ("IopCallDriverAddDevice:\t%s load driver\n", 02591 (LoadDriver ? "Will" : "Won't"))); 02592 02593 DebugPrint(1, ("IopCallDriverAddDevice:\tOpening registry key %wZ\n", 02594 &DeviceNode->InstancePath)); 02595 02596 // 02597 // Open the HKLM\System\CCS\Enum key. 02598 // 02599 02600 status = IopOpenRegistryKeyEx( &enumKey, 02601 NULL, 02602 &CmRegistryMachineSystemCurrentControlSetEnumName, 02603 KEY_READ 02604 ); 02605 02606 if (!NT_SUCCESS(status)) { 02607 DebugPrint(1, ("IopCallDriverAddDevice:\tUnable to open " 02608 "HKLM\\SYSTEM\\CCS\\ENUM\n")); 02609 return status; 02610 } 02611 02612 // 02613 // Open the instance key for this devnode 02614 // 02615 02616 status = IopOpenRegistryKeyEx( &instanceKey, 02617 enumKey, 02618 &DeviceNode->InstancePath, 02619 KEY_READ 02620 ); 02621 02622 ZwClose(enumKey); 02623 02624 if (!NT_SUCCESS(status)) { 02625 02626 DebugPrint(1, ("IopCallDriverAddDevice:\t\tError %#08lx opening enum key\n", 02627 status)); 02628 return status; 02629 } 02630 02631 // 02632 // Get the class value to locate the class key for this devnode 02633 // 02634 02635 status = IopGetRegistryValue(instanceKey, 02636 REGSTR_VALUE_CLASSGUID, 02637 &keyValueInformation); 02638 02639 if (NT_SUCCESS(status) && ((keyValueInformation->Type == REG_SZ) && 02640 (keyValueInformation->DataLength != 0))) { 02641 02642 HANDLE controlKey; 02643 UNICODE_STRING unicodeClassGuid; 02644 02645 IopRegistryDataToUnicodeString( 02646 &unicodeClassGuid, 02647 (PWSTR) KEY_VALUE_DATA(keyValueInformation), 02648 keyValueInformation->DataLength); 02649 02650 DebugPrint(1, ("IopCallDriverAddDevice:\t\tClass GUID is %wZ\n", 02651 &unicodeClassGuid)); 02652 02653 if (InitSafeBootMode) { 02654 if (!IopSafebootDriverLoad(&unicodeClassGuid)) { 02655 PKEY_VALUE_FULL_INFORMATION ClassValueInformation = NULL; 02656 NTSTATUS s; 02657 02658 // 02659 // don't load the driver 02660 // 02661 DbgPrint("SAFEBOOT: skipping device = %wZ\n",&unicodeClassGuid); 02662 s = IopGetRegistryValue(instanceKey, 02663 REGSTR_VAL_DEVDESC, 02664 &ClassValueInformation); 02665 if (NT_SUCCESS(s)) { 02666 UNICODE_STRING ClassString; 02667 02668 RtlInitUnicodeString(&ClassString, (PCWSTR) KEY_VALUE_DATA(ClassValueInformation)); 02669 02670 IopBootLog(&ClassString, FALSE); 02671 } else { 02672 IopBootLog(&unicodeClassGuid, FALSE); 02673 } 02674 return STATUS_UNSUCCESSFUL; 02675 } 02676 } 02677 02678 // 02679 // Open the class key 02680 // 02681 02682 status = IopOpenRegistryKeyEx( &controlKey, 02683 NULL, 02684 &CmRegistryMachineSystemCurrentControlSetControlClass, 02685 KEY_READ 02686 ); 02687 02688 if (!NT_SUCCESS(status)) { 02689 02690 DebugPrint(1, ("IopCallDriverAddDevice:\tUnable to open " 02691 "HKLM\\SYSTEM\\CCS\\CONTROL\\CLASS - %#08lx\n", 02692 status)); 02693 classKey = NULL; 02694 } else { 02695 02696 status = IopOpenRegistryKeyEx( &classKey, 02697 controlKey, 02698 &unicodeClassGuid, 02699 KEY_READ 02700 ); 02701 02702 ZwClose(controlKey); 02703 02704 if (!NT_SUCCESS(status)) { 02705 02706 DebugPrint(1, ("IopCallDriverAddDevice:\tUnable to open GUID key " 02707 "%wZ - %#08lx\n", 02708 &unicodeClassGuid, 02709 status)); 02710 02711 classKey = NULL; 02712 } 02713 } 02714 02715 if (classKey != NULL) { 02716 02717 UNICODE_STRING unicodeProperties; 02718 02719 RtlInitUnicodeString(&unicodeProperties, REGSTR_KEY_DEVICE_PROPERTIES ); 02720 02721 status = IopOpenRegistryKeyEx( &classPropsKey, 02722 classKey, 02723 &unicodeProperties, 02724 KEY_READ 02725 ); 02726 02727 if (!NT_SUCCESS(status)) { 02728 02729 DebugPrint(2, ("IopCallDriverAddDevice:\tUnable to open GUID\\Properties key " 02730 "%wZ - %#08lx\n", 02731 &unicodeClassGuid, 02732 status)); 02733 02734 classPropsKey = NULL; 02735 } 02736 } 02737 02738 ExFreePool(keyValueInformation); 02739 keyValueInformation = NULL; 02740 02741 } 02742 02743 // 02744 // Check to see if there's a service assigned to this device node. If 02745 // there's not then we can bail out without wasting too much time. 02746 // 02747 02748 RtlZeroMemory(&queryContext, sizeof(queryContext)); 02749 02750 queryContext.DeviceNode = DeviceNode; 02751 queryContext.LoadDriver = LoadDriver; 02752 02753 queryContext.AddContext = Context; 02754 02755 RtlZeroMemory(queryTable, sizeof(queryTable)); 02756 02757 queryTable[0].QueryRoutine = 02758 (PRTL_QUERY_REGISTRY_ROUTINE) IopCallDriverAddDeviceQueryRoutine; 02759 queryTable[0].Name = REGSTR_VAL_LOWERFILTERS; 02760 queryTable[0].EntryContext = (PVOID) UIntToPtr(LowerDeviceFilters); 02761 02762 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02763 (PWSTR) instanceKey, 02764 queryTable, 02765 &queryContext, 02766 NULL); 02767 if (NT_SUCCESS(status)) { 02768 02769 if (classKey != NULL) { 02770 02771 queryTable[0].QueryRoutine = 02772 (PRTL_QUERY_REGISTRY_ROUTINE) IopCallDriverAddDeviceQueryRoutine; 02773 queryTable[0].Name = REGSTR_VAL_LOWERFILTERS; 02774 queryTable[0].EntryContext = (PVOID) UIntToPtr(LowerClassFilters); 02775 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02776 (PWSTR) classKey, 02777 queryTable, 02778 &queryContext, 02779 NULL); 02780 } 02781 02782 if (NT_SUCCESS(status)) { 02783 queryTable[0].QueryRoutine = (PRTL_QUERY_REGISTRY_ROUTINE) IopCallDriverAddDeviceQueryRoutine; 02784 queryTable[0].Name = REGSTR_VALUE_SERVICE; 02785 queryTable[0].EntryContext = (PVOID) UIntToPtr(DeviceService); 02786 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 02787 02788 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02789 (PWSTR) instanceKey, 02790 queryTable, 02791 &queryContext, 02792 NULL); 02793 } 02794 } 02795 02796 if (DeviceNode->Flags & DNF_LEGACY_DRIVER) { 02797 02798 // 02799 // One of the services for this device is a legacy driver. Don't try 02800 // to add any filters since we'll just screw up the device stack. 02801 // 02802 02803 status = STATUS_SUCCESS; 02804 goto Cleanup; 02805 02806 } else if (NT_SUCCESS(status)) { 02807 02808 // 02809 // Call was successful so we must have been able to reference the 02810 // driver object. 02811 // 02812 02813 ASSERT(queryContext.DriverLists[DeviceService] != NULL); 02814 02815 if (queryContext.DriverLists[DeviceService]->NextEntry != NULL) { 02816 02817 // 02818 // There's more than one service assigned to this device. Configuration 02819 // error 02820 02821 DebugPrint(1, ("IopCallDriverAddDevice: Configuration Error - more " 02822 "than one service in driver list\n")); 02823 02824 IopSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY); 02825 02826 status = STATUS_UNSUCCESSFUL; 02827 02828 goto Cleanup; 02829 } 02830 // 02831 // this is the only case (FDO specified) where we can ignore PDO's characteristics 02832 // 02833 usePdoCharacteristics = FALSE; 02834 02835 } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) { 02836 02837 DebugPrint(1, ("IopCallDriverAddDevice\t\tError %#08lx reading service " 02838 "value for devnode %#08lx\n", status, DeviceNode)); 02839 02840 if (!IopDeviceNodeFlagsToCapabilities(DeviceNode)->RawDeviceOK) { 02841 02842 // 02843 // The device cannot be used raw. Bail out now. 02844 // 02845 02846 status = STATUS_UNSUCCESSFUL; 02847 goto Cleanup; 02848 02849 } else { 02850 02851 // 02852 // Raw device access is okay. 02853 // 02854 02855 IopClearDevNodeProblem(DeviceNode); 02856 02857 usePdoCharacteristics = TRUE; // shouldn't need to do this, but better be safe than sorry 02858 deviceRaw = TRUE; 02859 status = STATUS_SUCCESS; 02860 02861 } 02862 02863 } else { 02864 02865 // 02866 // something else went wrong while parsing the service key. The 02867 // query routine will have set the flags appropriately so we can 02868 // just bail out. 02869 // 02870 02871 goto Cleanup; 02872 02873 } 02874 02875 // 02876 // For each type of filter driver we want to build a list of the driver 02877 // objects to be loaded. We'll build all the driver lists if we can 02878 // and deal with error conditions afterwards. 02879 // 02880 02881 // 02882 // First get all the information we have to out of the instance key and 02883 // the device node. 02884 // 02885 02886 RtlZeroMemory(queryTable, sizeof(queryTable)); 02887 02888 queryTable[0].QueryRoutine = 02889 (PRTL_QUERY_REGISTRY_ROUTINE) IopCallDriverAddDeviceQueryRoutine; 02890 queryTable[0].Name = REGSTR_VAL_UPPERFILTERS; 02891 queryTable[0].EntryContext = (PVOID) UIntToPtr(UpperDeviceFilters); 02892 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02893 (PWSTR) instanceKey, 02894 queryTable, 02895 &queryContext, 02896 NULL); 02897 02898 if (NT_SUCCESS(status) && classKey) { 02899 queryTable[0].QueryRoutine = 02900 (PRTL_QUERY_REGISTRY_ROUTINE) IopCallDriverAddDeviceQueryRoutine; 02901 queryTable[0].Name = REGSTR_VAL_UPPERFILTERS; 02902 queryTable[0].EntryContext = (PVOID) UIntToPtr(UpperClassFilters); 02903 02904 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02905 (PWSTR) classKey, 02906 queryTable, 02907 &queryContext, 02908 NULL); 02909 } 02910 02911 if (NT_SUCCESS(status)) { 02912 02913 UCHAR serviceType = 0; 02914 PDRIVER_LIST_ENTRY listEntry = queryContext.DriverLists[serviceType]; 02915 02916 // 02917 // Make sure there's no more than one device service. Anything else is 02918 // a configuration error. 02919 // 02920 02921 ASSERT(!(DeviceNode->Flags & DNF_LEGACY_DRIVER)); 02922 ASSERT(!(DeviceNode->Flags & DNF_ADDED)); 02923 02924 ASSERTMSG( 02925 "Error - Device has no service but cannot be run RAW\n", 02926 ((queryContext.DriverLists[DeviceService] != NULL) || (deviceRaw))); 02927 02928 #ifndef NO_SPECIAL_IRP 02929 // 02930 // Grab the top of PDO stack 02931 // 02932 topOfPdoStack = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject); 02933 #endif 02934 02935 // 02936 // It's okay to try adding all the drivers. 02937 // 02938 for (serviceType = 0; serviceType < MaximumAddStage; serviceType++) { 02939 02940 DebugPrint(1, ("IopCallDriverAddDevice: Adding Services (type %d)\n", 02941 serviceType)); 02942 02943 if (serviceType == DeviceService) { 02944 02945 if (deviceRaw&&(queryContext.DriverLists[serviceType]==NULL)) { 02946 02947 // 02948 // Mark the devnode as added, as it has no service. 02949 // 02950 02951 ASSERT(queryContext.DriverLists[serviceType] == NULL); 02952 DeviceNode->Flags |= DNF_ADDED; 02953 02954 #ifndef NO_SPECIAL_IRP 02955 // 02956 // For the purpose of asserting IRPs, we mark the FDO. We 02957 // don't mark a raw PDO as the BOTTOM of the FDO stack as 02958 // that would be the lower filter in this case. 02959 // 02960 DeviceNode->PhysicalDeviceObject->DeviceObjectExtension->ExtensionFlags |= 02961 DOE_DESIGNATED_FDO | DOE_RAW_FDO; 02962 02963 } else { 02964 02965 // 02966 // Since we are going to see a service, grab a pointer to 02967 // the current top of the stack. While here, assert there 02968 // is exactly one service driver to load... 02969 // 02970 ASSERT(queryContext.DriverLists[serviceType]); 02971 ASSERT(!queryContext.DriverLists[serviceType]->NextEntry); 02972 topOfLowerFilterStack = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject); 02973 #endif 02974 } 02975 } 02976 02977 for (listEntry = queryContext.DriverLists[serviceType]; 02978 listEntry != NULL; 02979 listEntry = listEntry->NextEntry) { 02980 02981 PDRIVER_ADD_DEVICE addDeviceRoutine; 02982 02983 DebugPrint(1, ("IopCallDriverAddDevice:\tAdding driver %#08lx\n", 02984 listEntry->DriverObject)); 02985 02986 ASSERT(listEntry->DriverObject); 02987 ASSERT(listEntry->DriverObject->DriverExtension); 02988 ASSERT(listEntry->DriverObject->DriverExtension->AddDevice); 02989 02990 // 02991 // Invoke the driver's AddDevice() entry point. 02992 // 02993 addDeviceRoutine = 02994 listEntry->DriverObject->DriverExtension->AddDevice; 02995 02996 status = (addDeviceRoutine)(listEntry->DriverObject, 02997 DeviceNode->PhysicalDeviceObject); 02998 02999 DebugPrint(1, ("IopCallDriverAddDevice:\t\tRoutine returned " 03000 "%#08lx\n", status)); 03001 03002 if (NT_SUCCESS(status)) { 03003 03004 #ifndef NO_SPECIAL_IRP 03005 if (!deviceObjectHasBeenAttached) { 03006 03007 // 03008 // Mark the first driver loaded by this routine as the 03009 // bottom of the FDO stack. These must detach on a remove. 03010 // Note we can't simply flag the top of the stack, as 03011 // someone might attach in AddDevice... 03012 // 03013 fdoDeviceObject = topOfPdoStack->AttachedDevice; 03014 if (fdoDeviceObject) { 03015 03016 fdoDeviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_BOTTOM_OF_FDO_STACK; 03017 deviceObjectHasBeenAttached = TRUE; 03018 } 03019 } 03020 03021 // 03022 // Also note it is legal for a filter to succeed AddDevice 03023 // but fail to attach anything to the top of the stack. 03024 // 03025 if (serviceType == DeviceService) { 03026 03027 // 03028 // ADRIAO BUGBUG 10/07/98 - Since we are temporarily 03029 // letting successful but Noop'd AddDevice's through, 03030 // mark the stack appropriately. We will make it look 03031 // like a RAW FDO 03032 // 03033 fdoDeviceObject = topOfLowerFilterStack->AttachedDevice; 03034 03035 //ASSERT(fdoDeviceObject != NULL); 03036 03037 if (!fdoDeviceObject) { 03038 03039 // 03040 // Nope, didn't get an FDO. Mark the PDO raw. 03041 // ADRIAO BUGBUG 10/07/98 - 03042 // Another reason to complain about the legality 03043 // of succeeding a FDO AddDevice without attaching 03044 // anything - how does the PDO know he also has to 03045 // respond as an FDO???? 03046 // 03047 fdoDeviceObject = DeviceNode->PhysicalDeviceObject; 03048 fdoDeviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_RAW_FDO; 03049 } 03050 03051 // 03052 // Mark appropriate node "FDO". 03053 // 03054 fdoDeviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_DESIGNATED_FDO; 03055 } 03056 #endif 03057 03058 DeviceNode->Flags |= DNF_ADDED; 03059 } else if (serviceType == DeviceService) { 03060 03061 // 03062 // If filter drivers return failure, keep going. 03063 // 03064 03065 DeviceNode->Flags &= ~DNF_ADDED; 03066 IopSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_ADD); 03067 IopRequestDeviceRemoval(DeviceNode->PhysicalDeviceObject, CM_PROB_FAILED_ADD); 03068 goto Cleanup; 03069 } 03070 03071 if (IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject)->Flags & DO_DEVICE_INITIALIZING) { 03072 DebugPrint(1, ("***************** DO_DEVICE_INITIALIZING not cleared on %#08lx\n", 03073 IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject))); 03074 } 03075 03076 ASSERT_INITED(IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject)); 03077 } 03078 } 03079 03080 // 03081 // change PDO and all attached objects 03082 // to have properties specified in the registry 03083 // 03084 03085 IopChangeDeviceObjectFromRegistryProperties(DeviceNode->PhysicalDeviceObject, classPropsKey, instanceKey, usePdoCharacteristics); 03086 03087 // 03088 // CapabilityFlags are refreshed with call to IopDeviceCapabilitiesToRegistry after device is started 03089 // 03090 03091 } else { 03092 03093 DebugPrint(1, ("IopCallDriverAddDevice: Error %#08lx while building " 03094 "driver load list\n", status)); 03095 } 03096 03097 deviceObject = DeviceNode->PhysicalDeviceObject; 03098 03099 status = IopQueryLegacyBusInformation( 03100 deviceObject, 03101 NULL, 03102 &DeviceNode->InterfaceType, 03103 &DeviceNode->BusNumber 03104 ); 03105 03106 if (!NT_SUCCESS(status)) { 03107 03108 DeviceNode->InterfaceType = InterfaceTypeUndefined; 03109 DeviceNode->BusNumber = 0xfffffff0; 03110 03111 } 03112 03113 status = STATUS_SUCCESS; 03114 03115 Cleanup: 03116 { 03117 03118 UCHAR i; 03119 03120 DebugPrint(1, ("IopCallDriverAddDevice: DevNode flags leaving = %#08lx\n", 03121 DeviceNode->Flags)); 03122 03123 DebugPrint(1, ("IopCallDriverAddDevice: Cleaning up\n")); 03124 03125 // 03126 // Free the entries in the driver load list & release the references on 03127 // their driver objects. 03128 // 03129 03130 for (i = 0; i < MaximumAddStage; i++) { 03131 03132 PDRIVER_LIST_ENTRY listHead = queryContext.DriverLists[i]; 03133 03134 while(listHead != NULL) { 03135 03136 PDRIVER_LIST_ENTRY tmp = listHead; 03137 03138 listHead = listHead->NextEntry; 03139 03140 ASSERT(tmp->DriverObject != NULL); 03141 03142 ObDereferenceObject(tmp->DriverObject); 03143 03144 ExFreePool(tmp); 03145 } 03146 } 03147 } 03148 03149 ZwClose(instanceKey); 03150 03151 if (classKey != NULL) { 03152 ZwClose(classKey); 03153 } 03154 03155 if (classPropsKey != NULL) { 03156 ZwClose(classPropsKey); 03157 } 03158 03159 DebugPrint(1, ("IopCallDriverAddDevice: Returning status %#08lx\n", status)); 03160 03161 return status; 03162 } 03163 03164 NTSTATUS 03165 IopCallDriverAddDeviceQueryRoutine( 03166 IN PWSTR ValueName, 03167 IN ULONG ValueType, 03168 IN PWCHAR ValueData, 03169 IN ULONG ValueLength, 03170 IN PQUERY_CONTEXT Context, 03171 IN ULONG ServiceType 03172 ) 03173 03174 /*++ 03175 03176 Routine Description: 03177 03178 This routine is called to build a list of driver objects which need to 03179 be Added to a physical device object. Each time it is called with a 03180 service name it will locate a driver object for that device and append 03181 it to the proper driver list for the device node. 03182 03183 In the event a driver object cannot be located or that it cannot be loaded 03184 at this time, this routine will return an error and will set the flags 03185 in the device node in the context appropriately. 03186 03187 Arguments: 03188 03189 ValueName - the name of the value 03190 03191 ValueType - the type of the value 03192 03193 ValueData - the data in the value (unicode string data) 03194 03195 ValueLength - the number of bytes in the value data 03196 03197 Context - a structure which contains the device node, the context passed 03198 to IopCallDriverAddDevice and the driver lists for the device 03199 node. 03200 03201 EntryContext - the index of the driver list the routine should append 03202 nodes to. 03203 03204 Return Value: 03205 03206 STATUS_SUCCESS if the driver was located and added to the list 03207 successfully or if there was a non-fatal error while handling the 03208 driver. 03209 03210 an error value indicating why the driver could not be added to the list. 03211 03212 --*/ 03213 03214 { 03215 UNICODE_STRING unicodeServiceName; 03216 UNICODE_STRING unicodeDriverName; 03217 PKEY_VALUE_FULL_INFORMATION keyValueInformation; 03218 03219 ULONG i; 03220 ULONG loadType; 03221 03222 PWSTR prefixString = L"\\Driver\\"; 03223 BOOLEAN madeupService; 03224 03225 USHORT groupIndex; 03226 PDRIVER_OBJECT driverObject = NULL; 03227 03228 NTSTATUS status = STATUS_SUCCESS; 03229 BOOLEAN freeDriverName = FALSE; 03230 03231 DebugPrint(1, ("IopCallDriverAddDevice:\t\tValue %ws [Type %d, Len %d] @ " 03232 "%#08lx\n", 03233 ValueName, ValueType, ValueLength, ValueData)); 03234 03235 // 03236 // First check and make sure that the value type is okay. An invalid type 03237 // is not a fatal error. 03238 // 03239 03240 if (ValueType != REG_SZ) { 03241 03242 DebugPrint(1, ("IopCallDriverAddDevice:\t\tValueType %d invalid for " 03243 "ServiceType %d\n", 03244 ValueType, 03245 ServiceType)); 03246 03247 return STATUS_SUCCESS; 03248 } 03249 03250 // 03251 // Make sure the string is a reasonable length. 03252 // 03253 03254 if (ValueLength <= sizeof(WCHAR)) { 03255 03256 DebugPrint(1, ("IopCallDriverAddDevice:\t\tValueLength %d is too short\n", 03257 ValueLength)); 03258 03259 return STATUS_SUCCESS; 03260 } 03261 03262 RtlInitUnicodeString(&unicodeServiceName, ValueData); 03263 03264 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tService Name %wZ\n", 03265 &unicodeServiceName)); 03266 03267 // 03268 // Check the service name to see if it should be used directly to reference 03269 // the driver object. If the string begins with "\Driver", make sure the 03270 // madeupService flag is set. 03271 // 03272 03273 madeupService = TRUE; 03274 i = 0; 03275 03276 while(*prefixString != L'\0') { 03277 03278 if (unicodeServiceName.Buffer[i] != *prefixString) { 03279 03280 madeupService = FALSE; 03281 break; 03282 } 03283 03284 i++; 03285 prefixString++; 03286 } 03287 03288 if (madeupService) { 03289 03290 RtlInitUnicodeString(&unicodeDriverName, unicodeServiceName.Buffer); 03291 03292 groupIndex = 0; 03293 loadType = SERVICE_BOOT_START; 03294 03295 } else { 03296 03297 HANDLE serviceKey; 03298 03299 // 03300 // BUGBUG - (RBN) Hack to set the service name in the devnode if it 03301 // isn't already set. 03302 // 03303 // This probably should be done earlier somewhere else after the 03304 // INF is run, but if we don't do it now we'll blow up when we 03305 // call IopGetDriverLoadType below. 03306 // 03307 03308 if (Context->DeviceNode->ServiceName.Length == 0) { 03309 03310 Context->DeviceNode->ServiceName = unicodeServiceName; 03311 Context->DeviceNode->ServiceName.Buffer = ExAllocatePool( NonPagedPool, 03312 unicodeServiceName.MaximumLength ); 03313 03314 if (Context->DeviceNode->ServiceName.Buffer != NULL) { 03315 RtlCopyMemory( Context->DeviceNode->ServiceName.Buffer, 03316 unicodeServiceName.Buffer, 03317 unicodeServiceName.MaximumLength ); 03318 } else { 03319 RtlInitUnicodeString( &Context->DeviceNode->ServiceName, NULL ); 03320 03321 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tCannot allocate memory for service name in devnode\n")); 03322 03323 status = STATUS_UNSUCCESSFUL; 03324 03325 goto Cleanup; 03326 } 03327 } 03328 03329 // 03330 // Check in the registry to find the name of the driver object 03331 // for this device. 03332 // 03333 03334 status = IopOpenServiceEnumKeys(&unicodeServiceName, 03335 KEY_READ, 03336 &serviceKey, 03337 NULL, 03338 FALSE); 03339 03340 if (!NT_SUCCESS(status)) { 03341 03342 // 03343 // Cannot open the service key for this driver. This is a 03344 // fatal error. 03345 // 03346 03347 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tStatus %#08lx " 03348 "opening service key\n", 03349 status)); 03350 03351 IopSetDevNodeProblem(Context->DeviceNode, CM_PROB_REGISTRY); 03352 03353 goto Cleanup; 03354 } 03355 03356 groupIndex = IopGetGroupOrderIndex(serviceKey); 03357 03358 status = IopGetDriverNameFromKeyNode(serviceKey, &unicodeDriverName); 03359 03360 if (!NT_SUCCESS(status)) { 03361 03362 ZwClose(serviceKey); 03363 03364 // 03365 // Can't get the driver name from the service key. This is a 03366 // fatal error. 03367 // 03368 03369 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tStatus %#08lx " 03370 "getting driver name\n", 03371 status)); 03372 03373 IopSetDevNodeProblem(Context->DeviceNode, CM_PROB_REGISTRY); 03374 goto Cleanup; 03375 } else { 03376 freeDriverName = TRUE; 03377 } 03378 03379 loadType = SERVICE_DISABLED; 03380 03381 status = IopGetRegistryValue(serviceKey, L"Start", &keyValueInformation); 03382 if (NT_SUCCESS(status)) { 03383 if (keyValueInformation->Type == REG_DWORD) { 03384 if (keyValueInformation->DataLength == sizeof(ULONG)) { 03385 loadType = *(PULONG)KEY_VALUE_DATA(keyValueInformation); 03386 } 03387 } 03388 ExFreePool(keyValueInformation); 03389 } 03390 03391 ZwClose(serviceKey); 03392 } 03393 03394 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tDriverName is %wZ\n", 03395 &unicodeDriverName)); 03396 03397 driverObject = IopReferenceDriverObjectByName(&unicodeDriverName); 03398 03399 if (driverObject == NULL) { 03400 03401 PWCHAR buffer; 03402 UNICODE_STRING unicodeServicePath; 03403 03404 // 03405 // We couldn't find a driver object. It's possible the driver isn't 03406 // loaded & initialized so check to see if we can try to load it 03407 // now. 03408 // 03409 03410 if (madeupService) { 03411 03412 // 03413 // The madeup service's driver doesn't seem to exist yet. 03414 // We will fail the request without setting DNF_ADD_FAILED such that 03415 // we will try it again later. (Root Enumerated devices...) 03416 // 03417 03418 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tCannot find driver " 03419 "object for madeup service\n")); 03420 03421 status = STATUS_UNSUCCESSFUL; 03422 03423 goto Cleanup; 03424 } 03425 03426 if (ServiceType != DeviceService && !PnPBootDriversInitialized) { 03427 03428 // 03429 // If we are in BootDriverInitialization phase and trying to load a filter driver 03430 // 03431 03432 driverObject = IopLoadBootFilterDriver(&unicodeDriverName, groupIndex); 03433 if (driverObject == NULL) { 03434 status = STATUS_UNSUCCESSFUL; 03435 goto Cleanup; 03436 } 03437 } else { 03438 if (!Context->LoadDriver) { 03439 03440 // 03441 // We're not supposed to try and load a driver - most likely our 03442 // disk drivers aren't initialized yet. We need to stop the add 03443 // process but we can't mark the devnode as failed or we won't 03444 // be called again when we can load the drivers. 03445 // 03446 03447 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tNot allowed to load " 03448 "drivers yet\n")); 03449 03450 status = STATUS_UNSUCCESSFUL; 03451 goto Cleanup; 03452 } 03453 03454 if (groupIndex > Context->AddContext->GroupsToStart) { 03455 03456 // 03457 // We're not allowed to initialize this driver until drivers in 03458 // previous groups are loaded. Leave the devnode flags untouched 03459 // so we get called again, but stop the add process now. 03460 // 03461 03462 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tLower group drivers " 03463 "have not been initialized yet\n")); 03464 if (groupIndex < Context->AddContext->GroupToStartNext) { 03465 Context->AddContext->GroupToStartNext = groupIndex; 03466 } 03467 03468 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tGroup = %d, To Start = " 03469 "Start Next = %d\n", 03470 groupIndex, 03471 Context->AddContext->GroupsToStart, 03472 Context->AddContext->GroupToStartNext)); 03473 03474 status = STATUS_UNSUCCESSFUL; 03475 goto Cleanup; 03476 } 03477 03478 03479 03480 if (loadType > Context->AddContext->DriverStartType) { 03481 03482 if (loadType == SERVICE_DISABLED && 03483 !IopDoesDevNodeHaveProblem(Context->DeviceNode)) { 03484 IopSetDevNodeProblem(Context->DeviceNode, CM_PROB_DISABLED_SERVICE); 03485 } 03486 03487 // 03488 // The service is either disabled or we are not at the right 03489 // time to load it. Don't load it, but make sure we can get 03490 // called again. If a service is marked as demand start, we 03491 // always load it. 03492 // 03493 03494 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tService is disabled or not at right time to load it\n")); 03495 status = STATUS_UNSUCCESSFUL; 03496 goto Cleanup; 03497 } 03498 03499 { 03500 HANDLE handle; 03501 03502 // 03503 // Check in the registry to find the name of the driver object 03504 // for this device. 03505 // 03506 03507 status = IopOpenServiceEnumKeys(&unicodeServiceName, 03508 KEY_READ, 03509 &handle, 03510 NULL, 03511 FALSE); 03512 03513 if (!NT_SUCCESS(status)) { 03514 03515 // 03516 // Cannot open the service key for this driver. This is a 03517 // fatal error. 03518 // 03519 03520 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tStatus %#08lx " 03521 "opening service key\n", 03522 status)); 03523 } else { 03524 status = IopLoadDriver(handle,FALSE); // handle will be closed by IopLoadDriver 03525 03526 if (PnPInitialized) { 03527 03528 PLIST_ENTRY entry; 03529 PREINIT_PACKET reinitEntry; 03530 03531 // 03532 // Walk the list reinitialization list in case this driver, or 03533 // some other driver, has requested to be invoked at a re- 03534 // initialization entry point. 03535 // 03536 03537 while (entry = ExInterlockedRemoveHeadList( &IopDriverReinitializeQueueHead, &IopDatabaseLock )) { 03538 reinitEntry = CONTAINING_RECORD( entry, REINIT_PACKET, ListEntry ); 03539 reinitEntry->DriverObject->DriverExtension->Count++; 03540 reinitEntry->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED; 03541 reinitEntry->DriverReinitializationRoutine( reinitEntry->DriverObject, 03542 reinitEntry->Context, 03543 reinitEntry->DriverObject->DriverExtension->Count ); 03544 ExFreePool( reinitEntry ); 03545 } 03546 } 03547 } 03548 03549 } 03550 if (!NT_SUCCESS(status)) { 03551 03552 if (PnPBootDriversInitialized) { 03553 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tStatus %#08lx " 03554 "from loading driver\n", status)); 03555 } 03556 } 03557 03558 } 03559 } else { 03560 ObDereferenceObject(driverObject); 03561 if (!(driverObject->Flags & DRVO_INITIALIZED)) { 03562 status = STATUS_UNSUCCESSFUL; 03563 goto Cleanup; 03564 } 03565 } 03566 03567 // 03568 // Ignore the return value from the driver load - just try and get a 03569 // pointer to the driver object for the service. 03570 // 03571 03572 driverObject = IopReferenceDriverObjectByName(&unicodeDriverName); 03573 03574 if (driverObject == NULL) { 03575 03576 if (PnPBootDriversInitialized) { 03577 03578 // 03579 // Apparently the load didn't work out very well. This is a 03580 // fatal error. 03581 // 03582 03583 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tUnable to reference " 03584 "driver %wZ\n", &unicodeDriverName)); 03585 03586 if (!IopDoesDevNodeHaveProblem(Context->DeviceNode)) { 03587 IopSetDevNodeProblem(Context->DeviceNode, CM_PROB_FAILED_ADD); 03588 } 03589 } 03590 03591 status = STATUS_UNSUCCESSFUL; 03592 goto Cleanup; 03593 } else if (!(driverObject->Flags & DRVO_INITIALIZED)) { 03594 ObDereferenceObject(driverObject); 03595 status = STATUS_UNSUCCESSFUL; 03596 goto Cleanup; 03597 } 03598 03599 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tDriver Reference %#08lx\n", 03600 driverObject)); 03601 03602 // 03603 // Check to see if the driver is a legacy driver rather than a Pnp one. 03604 // 03605 03606 if (IopIsLegacyDriver(driverObject)) { 03607 03608 // 03609 // It is. Since the legacy driver may have already obtained a 03610 // handle to the device object, we need to assume this device 03611 // has been added and started. 03612 // 03613 03614 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tDriver is a legacy " 03615 "driver\n")); 03616 03617 if (ServiceType == DeviceService) { 03618 Context->DeviceNode->Flags |= DNF_ADDED + 03619 DNF_STARTED + 03620 DNF_LEGACY_DRIVER; 03621 03622 status = STATUS_UNSUCCESSFUL; 03623 } else { 03624 03625 // 03626 // We allow someone to plug in a legacy driver as a filter driver. 03627 // In this case, the legacy driver will be loaded but will not be part 03628 // of our pnp driver stack. 03629 // 03630 03631 status = STATUS_SUCCESS; 03632 } 03633 goto Cleanup; 03634 } 03635 03636 // 03637 // There's a chance the driver detected this PDO during it's driver entry 03638 // routine. If it did then just bail out. 03639 // 03640 03641 if (!OK_TO_ADD_DEVICE(Context->DeviceNode)) { 03642 03643 DebugPrint(1, ("IopCallDriverAddDevice\t\t\tDevNode was reported " 03644 "as detected during driver entry\n")); 03645 status = STATUS_UNSUCCESSFUL; 03646 goto Cleanup; 03647 } 03648 03649 // 03650 // Add the driver to the list. 03651 // 03652 03653 { 03654 PDRIVER_LIST_ENTRY listEntry; 03655 PDRIVER_LIST_ENTRY *runner = &(Context->DriverLists[ServiceType]); 03656 03657 status = STATUS_SUCCESS; 03658 03659 // 03660 // Allocate a new list entry to queue this driver object for the caller 03661 // 03662 03663 listEntry = ExAllocatePool(PagedPool, sizeof(DRIVER_LIST_ENTRY)); 03664 03665 if (listEntry == NULL) { 03666 03667 DebugPrint(1, ("IopCallDriverAddDevice:\t\t\tUnable to allocate list " 03668 "entry\n")); 03669 03670 status = STATUS_INSUFFICIENT_RESOURCES; 03671 goto Cleanup; 03672 } 03673 03674 listEntry->DriverObject = driverObject; 03675 listEntry->NextEntry = NULL; 03676 03677 while(*runner != NULL) { 03678 runner = &((*runner)->NextEntry); 03679 } 03680 03681 *runner = listEntry; 03682 } 03683 03684 Cleanup: 03685 03686 if (freeDriverName) { 03687 RtlFreeUnicodeString(&unicodeDriverName); 03688 } 03689 return status; 03690 } 03691 03692 03693 NTSTATUS 03694 IopQueryDeviceCapabilities( 03695 IN PDEVICE_NODE DeviceNode, 03696 OUT PDEVICE_CAPABILITIES Capabilities 03697 ) 03698 03699 /*++ 03700 03701 Routine Description: 03702 03703 This routine will issue an irp to the DeviceObject to retrieve the 03704 pnp device capabilities. 03705 Should only be called twice - first from IopProcessNewDeviceNode, 03706 and second from IopDeviceNodeCapabilitiesToRegistry, called after 03707 device is started. If you consider calling this device, see if 03708 DeviceNode->CapabilityFlags does what you need instead (accessed 03709 via IopDeviceNodeFlagsToCapabilities(...). 03710 03711 Arguments: 03712 03713 DeviceNode - the device object the request should be sent to. 03714 03715 Capabilities - a capabilities structure to be filled in by the driver. 03716 03717 Return Value: 03718 03719 status 03720 03721 --*/ 03722 03723 { 03724 IO_STACK_LOCATION irpStack; 03725 PVOID dummy; 03726 03727 NTSTATUS status; 03728 03729 // 03730 // Initialize the capabilities structure. 03731 // 03732 03733 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); 03734 Capabilities->Size = sizeof(DEVICE_CAPABILITIES); 03735 Capabilities->Version = 1; 03736 Capabilities->Address = Capabilities->UINumber = (ULONG)-1; 03737 03738 // 03739 // Initialize the stack location to pass to IopSynchronousCall() 03740 // 03741 03742 RtlZeroMemory(&irpStack, sizeof(IO_STACK_LOCATION)); 03743 03744 // 03745 // Query the device's capabilities 03746 // 03747 03748 irpStack.MajorFunction = IRP_MJ_PNP; 03749 irpStack.MinorFunction = IRP_MN_QUERY_CAPABILITIES; 03750 irpStack.Parameters.DeviceCapabilities.Capabilities = Capabilities; 03751 03752 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, 03753 &irpStack, 03754 &dummy); 03755 03756 ASSERT(status != STATUS_PENDING); 03757 03758 return status; 03759 } 03760 03761 BOOLEAN 03762 IopProcessCriticalDevice( 03763 IN PDEVICE_NODE DeviceNode 03764 ) 03765 03766 /*++ 03767 03768 Routine Description: 03769 03770 This routine will check whether the device is a "critical" one (see the 03771 top of this file for a description of critical). If the device is critical 03772 then it will be assigned a service based on the contents of 03773 IopCriticalDeviceList. 03774 03775 Arguments: 03776 03777 DeviceNode - the device node to process 03778 03779 Return Value: 03780 03781 TRUE if the device is critical 03782 FALSE otherwise 03783 03784 --*/ 03785 03786 { 03787 HANDLE enumKey; 03788 HANDLE instanceKey; 03789 03790 UNICODE_STRING service, classGuid, lowerFilters, upperFilters; 03791 BOOLEAN foundMatch = FALSE; 03792 03793 RTL_QUERY_REGISTRY_TABLE queryTable[2]; 03794 03795 NTSTATUS status; 03796 03797 #if DBG_SCOPE 03798 PWCHAR str; 03799 ULONG length; 03800 #endif 03801 03802 DebugPrint(1, ("IopIsCriticalPnpDevice called for devnode %#08lx\n", DeviceNode)); 03803 03804 // 03805 // Open the HKLM\System\CCS\Enum key. 03806 // 03807 03808 status = IopOpenRegistryKeyEx( &enumKey, 03809 NULL, 03810 &CmRegistryMachineSystemCurrentControlSetEnumName, 03811 KEY_READ 03812 ); 03813 03814 if (!NT_SUCCESS(status)) { 03815 DebugPrint(1, ("IICPD: couldn't open enum key %#08lx\n", status)); 03816 return FALSE; 03817 } 03818 03819 // 03820 // Open the instance key for this devnode 03821 // 03822 03823 status = IopOpenRegistryKeyEx( &instanceKey, 03824 enumKey, 03825 &DeviceNode->InstancePath, 03826 KEY_ALL_ACCESS 03827 ); 03828 03829 ZwClose(enumKey); 03830 03831 // 03832 // First determine if this is a critical device type 03833 // 03834 03835 if (!NT_SUCCESS(status)) { 03836 DebugPrint(1, ("IICPD: couldn't open instance path key %wZ [%#08lx]\n", 03837 &(DeviceNode->InstancePath))); 03838 ZwClose(instanceKey); 03839 return FALSE; 03840 03841 } else { 03842 // 03843 // Call IopProcessCriticalDeviceRoutine to 03844 // enumerate entries in the CriticalDeviceDatabase 03845 // and compare with HardwareId and CompatibleIds 03846 // value data from instanceKey. 03847 // 03848 RtlInitUnicodeString(&service, NULL); 03849 RtlInitUnicodeString(&classGuid, NULL); 03850 RtlInitUnicodeString(&lowerFilters, NULL); 03851 RtlInitUnicodeString(&upperFilters, NULL); 03852 status = IopProcessCriticalDeviceRoutine(instanceKey, 03853 &foundMatch, 03854 &service, 03855 &classGuid, 03856 &lowerFilters, 03857 &upperFilters); 03858 if (!NT_SUCCESS(status)) { 03859 DebugPrint(1, ("IICPD: IopProcessCriticalDeviceRoutine failed with status %#08lx\n", status)); 03860 return FALSE; 03861 } 03862 03863 } 03864 03865 // 03866 // If we get here then this is a "critical" device and we know the service 03867 // to setup for it. Set the service value in the registry. 03868 // 03869 03870 if (!foundMatch) { 03871 ZwClose(instanceKey); 03872 return FALSE; 03873 03874 } else { 03875 UNICODE_STRING serviceValue, classGuidValue, lowerFiltersValue, 03876 upperFiltersValue; 03877 03878 DebugPrint(1, ("IopProcessCriticalDevice: Setting up critical service\n")); 03879 03880 RtlInitUnicodeString(&serviceValue, REGSTR_VALUE_SERVICE); 03881 RtlInitUnicodeString(&classGuidValue, REGSTR_VALUE_CLASSGUID); 03882 RtlInitUnicodeString(&lowerFiltersValue, REGSTR_VALUE_LOWERFILTERS); 03883 RtlInitUnicodeString(&upperFiltersValue, REGSTR_VALUE_UPPERFILTERS); 03884 03885 if (classGuid.Buffer) { 03886 DebugPrint(1, ("IopProcessCriticalDevice: classGuid is %wZ\n", 03887 &classGuid)); 03888 status = ZwSetValueKey(instanceKey, 03889 &classGuidValue, 03890 0L, 03891 REG_SZ, 03892 classGuid.Buffer, 03893 classGuid.Length + sizeof(UNICODE_NULL)); 03894 } 03895 if (lowerFilters.Buffer) { 03896 #if DBG_SCOPE 03897 str = lowerFilters.Buffer; 03898 while ((length = wcslen(str)) != 0) { 03899 DebugPrint(1, ("IopProcessCriticalDevice: lower filter is %ws\n", 03900 str)); 03901 str += (length + 1); 03902 } 03903 #endif 03904 status = ZwSetValueKey(instanceKey, 03905 &lowerFiltersValue, 03906 0L, 03907 REG_MULTI_SZ, 03908 lowerFilters.Buffer, 03909 lowerFilters.Length); // + sizeof(UNICODE_NULL)); 03910 } 03911 03912 if (upperFilters.Buffer) { 03913 #if DBG_SCOPE 03914 str = upperFilters.Buffer; 03915 while ((length = wcslen(str)) != 0) { 03916 DebugPrint(1, ("IopProcessCriticalDevice: upper filter is %ws\n", 03917 str)); 03918 str += (length + 1); 03919 } 03920 #endif 03921 status = ZwSetValueKey(instanceKey, 03922 &upperFiltersValue, 03923 0L, 03924 REG_MULTI_SZ, 03925 upperFilters.Buffer, 03926 upperFilters.Length); // + sizeof(UNICODE_NULL)); 03927 } 03928 03929 DebugPrint(1, ("IopProcessCriticalDevice: service is %wZ\n", 03930 &service)); 03931 status = ZwSetValueKey(instanceKey, 03932 &serviceValue, 03933 0L, 03934 REG_SZ, 03935 service.Buffer, 03936 service.Length + sizeof(UNICODE_NULL)); 03937 03938 // 03939 // If the service was set properly set the CONFIGFLAG_FINISH_INSTALL so 03940 // we will still get a new hw found popup and go through the class 03941 // installer. 03942 // 03943 03944 if (NT_SUCCESS(status)) { 03945 03946 UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 03947 UNICODE_STRING valueName; 03948 PKEY_VALUE_PARTIAL_INFORMATION keyInfo = 03949 (PKEY_VALUE_PARTIAL_INFORMATION) buffer; 03950 ULONG flags = 0; 03951 03952 ULONG length; 03953 03954 NTSTATUS tmpStatus; 03955 03956 RtlInitUnicodeString(&valueName, REGSTR_VALUE_CONFIG_FLAGS); 03957 03958 tmpStatus = ZwQueryValueKey(instanceKey, 03959 &valueName, 03960 KeyValuePartialInformation, 03961 keyInfo, 03962 sizeof(buffer), 03963 &length); 03964 03965 if (NT_SUCCESS(tmpStatus) && (keyInfo->Type == REG_DWORD)) { 03966 03967 flags = *(PULONG)keyInfo->Data; 03968 } 03969 03970 flags &= ~(CONFIGFLAG_REINSTALL | CONFIGFLAG_FAILEDINSTALL); 03971 flags |= CONFIGFLAG_FINISH_INSTALL; 03972 03973 ZwSetValueKey(instanceKey, 03974 &valueName, 03975 0L, 03976 REG_DWORD, 03977 &flags, 03978 sizeof(ULONG)); 03979 03980 ASSERT(!IopDoesDevNodeHaveProblem(DeviceNode) || 03981 IopIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) || 03982 IopIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) || 03983 IopIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL)); 03984 03985 IopClearDevNodeProblem(DeviceNode); 03986 } 03987 ZwClose(instanceKey); 03988 } 03989 03990 IopFreeAllocatedUnicodeString(&service); 03991 IopFreeAllocatedUnicodeString(&classGuid); 03992 IopFreeAllocatedUnicodeString(&lowerFilters); 03993 IopFreeAllocatedUnicodeString(&upperFilters); 03994 03995 return (NT_SUCCESS(status)); 03996 } 03997 03998 03999 NTSTATUS 04000 IopProcessCriticalDeviceRoutine( 04001 IN HANDLE HDevInstance, 04002 IN PBOOLEAN FoundMatch, 04003 IN PUNICODE_STRING ServiceName, 04004 IN PUNICODE_STRING ClassGuid, 04005 IN PUNICODE_STRING LowerFilters, 04006 IN PUNICODE_STRING UpperFilters 04007 ) 04008 04009 /*++ 04010 04011 04012 Routine Description: 04013 04014 This routine will enumerate all values of the CriticalDeviceDatabase 04015 registry key, and compare each with entries within 04016 the HardwareId and CompatibleIds values of key associated 04017 with the current device instance. 04018 04019 Arguments: 04020 04021 HDevInstance - HANDLE to device instance. 04022 04023 FoundMatch - receives TRUE if a match was found. 04024 04025 ServiceName - receives name of service to be assigned to 04026 the device instance pointed to by 04027 HDevInstance. 04028 04029 Return Value: 04030 04031 NTSTATUS code 04032 04033 STATUS_SUCCESS 04034 STATUS_INVALID_PARAMETER 04035 04036 --*/ 04037 04038 { 04039 NTSTATUS status; 04040 HANDLE hRegistryMachine, hCriticalDeviceKey, 04041 hCriticalEntry; 04042 PWSTR keyValueInfoTag[2]; 04043 PKEY_VALUE_FULL_INFORMATION keyValueInfo[2], matchedKeyValFullInfo; 04044 BUFFER_INFO infoBuffer; 04045 ULONG enumIndex, idIndex, resultSize, stringLength; 04046 UNICODE_STRING tmpUnicodeString, unicodeCriticalEntry, 04047 unicodeCriticalDeviceKeyName; 04048 PWCHAR stringStart, bufferEnd, ptr; 04049 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 04050 04051 #define INITIAL_INFOBUFFER_SIZE sizeof(KEY_VALUE_FULL_INFORMATION) + 8*sizeof(WCHAR) + 255*sizeof(WCHAR) 04052 04053 hRegistryMachine = NULL; 04054 hCriticalDeviceKey = NULL; 04055 infoBuffer.Buffer = NULL; 04056 04057 // 04058 // Read Key Value Information 04059 // from HardwareId and CompatibleIds values 04060 // 04061 // keyValueInfo[idIndex == 0] == REGSTR_VAL_HARDWAREID == "HardwareId" 04062 // keyValueInfo[idIndex == 1] == REGSTR_VAL_COMPATIBLEIDS == "CompatibleIds" 04063 // 04064 keyValueInfoTag[0] = REGSTR_VAL_HARDWAREID; 04065 keyValueInfoTag[1] = REGSTR_VAL_COMPATIBLEIDS; 04066 04067 for (idIndex = 0; idIndex < 2; idIndex++) { 04068 04069 keyValueInfo[idIndex] = NULL; 04070 status = IopGetRegistryValue(HDevInstance, 04071 keyValueInfoTag[idIndex], 04072 &keyValueInfo[idIndex]); 04073 if (!NT_SUCCESS( status )) { 04074 04075 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: Unable to get some " 04076 "%ws value info, %#08lx. continuing.\n", 04077 keyValueInfoTag[idIndex], status)); 04078 04079 } else if ((keyValueInfo[idIndex]->Type != REG_MULTI_SZ) || 04080 (keyValueInfo[idIndex]->DataLength == 0)) { 04081 04082 ExFreePool(keyValueInfo[idIndex]); 04083 keyValueInfo[idIndex] = NULL; 04084 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: some %ws" 04085 "Key Value Info not in expected format\n", 04086 keyValueInfoTag[idIndex])); 04087 } else { 04088 04089 // 04090 // It is good, make sure all of the IDs match '\' replacement policy 04091 // 04092 tmpUnicodeString.Buffer = (PWCHAR) KEY_VALUE_DATA(keyValueInfo[idIndex]); 04093 tmpUnicodeString.Length = (USHORT) keyValueInfo[idIndex]->DataLength; 04094 tmpUnicodeString.MaximumLength = tmpUnicodeString.Length; 04095 04096 IopReplaceSeperatorWithPound(&tmpUnicodeString, 04097 &tmpUnicodeString); 04098 } 04099 } 04100 04101 // 04102 // Get handle to \REGISTRY\MACHINE registry key. 04103 // 04104 status = IopOpenRegistryKeyEx( &hRegistryMachine, 04105 NULL, 04106 &CmRegistryMachineName, 04107 KEY_READ 04108 ); 04109 if (!NT_SUCCESS(status)) { 04110 goto cleanup; 04111 } 04112 04113 // 04114 // Open CriticalDeviceDatabase registry key to enumerate through. 04115 // 04116 // This key contains hardware id's for so called "critical" devices. These 04117 // are devices for which, for one reason or another, we cannot wait for 04118 // config manager to bring them on line. These are primarily devices which 04119 // are necessary in order to bring the system up into user mode so that 04120 // config manager can be run (disks, keyboards, video, etc...) 04121 // 04122 PiWstrToUnicodeString(&unicodeCriticalDeviceKeyName, REGSTR_PATH_CRITICALDEVICEDATABASE); 04123 status = IopOpenRegistryKeyEx( &hCriticalDeviceKey, 04124 hRegistryMachine, 04125 &unicodeCriticalDeviceKeyName, 04126 KEY_READ 04127 ); 04128 // 04129 // Close handle to \REGISTRY\MACHINE. 04130 // 04131 ZwClose(hRegistryMachine); 04132 04133 // 04134 // Check success in opening CriticalDeviceDatabase key. 04135 // 04136 if ( !NT_SUCCESS(status) ) { 04137 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: Unable to open %wZ key. exiting...\n", 04138 &unicodeCriticalDeviceKeyName)); 04139 goto cleanup; 04140 } 04141 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: Successfully opened %wZ key.\n", 04142 &unicodeCriticalDeviceKeyName)); 04143 04144 // 04145 // Allocate a buffer to store KeyValueFullInformation 04146 // of values from CriticalDeviceDatabase key. 04147 // 04148 status = IopAllocateBuffer( &infoBuffer, 04149 INITIAL_INFOBUFFER_SIZE ); 04150 if (!NT_SUCCESS(status)) { 04151 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: Unable to allocate buffer to hold key values. exiting...\n", 04152 &unicodeCriticalDeviceKeyName)); 04153 goto cleanup; 04154 } 04155 04156 // 04157 // Enumerate through Critical Device entries. 04158 // 04159 // For each CriticalDeviceDatabase value entry compare with all entries of HardwareId 04160 // and CompatibleIds REG_MULTI_SZ for a match 04161 // 04162 enumIndex = 0; 04163 while (((status = ZwEnumerateKey( hCriticalDeviceKey, 04164 enumIndex, 04165 KeyBasicInformation, 04166 (PVOID) infoBuffer.Buffer, 04167 infoBuffer.MaxSize, 04168 &resultSize)) != STATUS_NO_MORE_ENTRIES)) { 04169 if (status == STATUS_BUFFER_OVERFLOW) { 04170 // 04171 // Buffer allocated to hold value was too small; 04172 // resize to specified length, and try again. 04173 // 04174 status = IopResizeBuffer( &infoBuffer, 04175 resultSize, 04176 FALSE ); 04177 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: ZwEnumerateKey returned STATUS_BUFFER_OVERFLOW, %#08lx\n", 04178 status)); 04179 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: (resizing buffer...)\n")); 04180 continue; 04181 04182 } else if (!NT_SUCCESS(status)) { 04183 // 04184 // ZwEnumerateKey returned failure status other than 04185 // STATUS_NO_MORE_ENTRIES or STATUS_BUFFER_OVERFLOW. 04186 // 04187 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: ZwEnumerateValueKey failed, %#08lx exiting...\n", 04188 status)); 04189 goto cleanup; 04190 } 04191 // 04192 // Store CriticalDeviceDatabase entry in a unicode string to do 04193 // case-insensitive comparisons with HardwareId/CompatibleIds entries 04194 // from the new device's instance key. 04195 // 04196 04197 unicodeCriticalEntry.Buffer = ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->Name; 04198 unicodeCriticalEntry.Length = (USHORT) ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->NameLength; 04199 unicodeCriticalEntry.MaximumLength = unicodeCriticalEntry.Length; 04200 04201 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: \t key (%u) enumerated: %wZ\n", 04202 enumIndex, 04203 &unicodeCriticalEntry)); 04204 04205 04206 // 04207 // Look at HardwareId and CompatibleIds of new device... 04208 // 04209 for ( idIndex=0; idIndex < 2; idIndex++) { 04210 04211 if (!keyValueInfo[idIndex]){ 04212 // 04213 // keyValueInfo[idIndex == 0] == REGSTR_VAL_HARDWAREID 04214 // keyValueInfo[idIndex == 1] == REGSTR_VAL_COMPATIBLEIDS 04215 // 04216 // Corresponding HardwareId or CompatibleIds value entry was invalid or not found. 04217 // keyValueInfo[idIndex] set to NULL above when 04218 // Type != REG_MULTI_SZ or DataLength == 0 04219 // Just skip, and move on. 04220 // 04221 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: No %ws value was found, move on to next\n", 04222 keyValueInfoTag[idIndex])); 04223 continue; 04224 } 04225 04226 // 04227 // Find start and end of this REG_MULTI_SZ 04228 // 04229 ptr = (PWCHAR)KEY_VALUE_DATA(keyValueInfo[idIndex]); 04230 stringStart = ptr; 04231 bufferEnd = (PWCHAR)((PUCHAR)ptr + keyValueInfo[idIndex]->DataLength); 04232 04233 while(ptr != bufferEnd) { 04234 04235 if (!*ptr) { 04236 // 04237 // Found null-terminated end of a single SZ within the MULTI_SZ. 04238 // 04239 stringLength = (ULONG)((PUCHAR)ptr - (PUCHAR)stringStart); 04240 tmpUnicodeString.Buffer = stringStart; 04241 tmpUnicodeString.Length = (USHORT)stringLength; 04242 tmpUnicodeString.MaximumLength = (USHORT)stringLength + sizeof(UNICODE_NULL); 04243 04244 DebugPrint(2, ("IopProcessCriticalDeviceRoutine: comparing %wZ with %wZ\n", 04245 &tmpUnicodeString, &unicodeCriticalEntry)); 04246 // 04247 // Check for a case-insenitive unicode string match. 04248 // 04249 if (RtlEqualUnicodeString(&tmpUnicodeString, 04250 &unicodeCriticalEntry, 04251 TRUE)) { 04252 04253 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: ***** Critical Device %wZ: Matched to Device %wZ.\n", 04254 &tmpUnicodeString, 04255 &unicodeCriticalEntry)); 04256 04257 #define NUM_QUERIES 4 04258 status = IopOpenRegistryKeyEx( &hCriticalEntry, 04259 hCriticalDeviceKey, 04260 &unicodeCriticalEntry, 04261 KEY_READ 04262 ); 04263 04264 if (!NT_SUCCESS(status)) { 04265 goto cleanup; 04266 } 04267 04268 parameters = (PRTL_QUERY_REGISTRY_TABLE) 04269 ExAllocatePool(NonPagedPool, 04270 sizeof(RTL_QUERY_REGISTRY_TABLE)*(NUM_QUERIES+1)); 04271 04272 if (!parameters) { 04273 ZwClose(hCriticalEntry); 04274 status = STATUS_INSUFFICIENT_RESOURCES; 04275 goto cleanup; 04276 } 04277 04278 RtlZeroMemory(parameters, 04279 sizeof(RTL_QUERY_REGISTRY_TABLE) * (NUM_QUERIES + 1)); 04280 04281 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 04282 parameters[0].Name = REGSTR_VALUE_SERVICE; 04283 parameters[0].EntryContext = ServiceName; 04284 parameters[0].DefaultType = REG_SZ; 04285 parameters[0].DefaultData = L""; 04286 parameters[0].DefaultLength = 0; 04287 04288 parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 04289 parameters[1].Name = REGSTR_VALUE_CLASSGUID; 04290 parameters[1].EntryContext = ClassGuid; 04291 parameters[1].DefaultType = REG_SZ; 04292 parameters[1].DefaultData = L""; 04293 parameters[1].DefaultLength = 0; 04294 04295 parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND; 04296 parameters[2].Name = REGSTR_VALUE_LOWERFILTERS; 04297 parameters[2].EntryContext = LowerFilters; 04298 parameters[2].DefaultType = REG_MULTI_SZ; 04299 parameters[2].DefaultData = L""; 04300 parameters[2].DefaultLength = 0; 04301 04302 parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND; 04303 parameters[3].Name = REGSTR_VALUE_UPPERFILTERS; 04304 parameters[3].EntryContext = UpperFilters; 04305 parameters[3].DefaultType = REG_MULTI_SZ; 04306 parameters[3].DefaultData = L""; 04307 parameters[3].DefaultLength = 0; 04308 04309 status = RtlQueryRegistryValues( 04310 RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL, 04311 (PWSTR) hCriticalEntry, 04312 parameters, 04313 NULL, 04314 NULL 04315 ); 04316 04317 ExFreePool(parameters); 04318 ZwClose(hCriticalEntry); 04319 04320 if (NT_SUCCESS(status)) { 04321 04322 // 04323 // Sanity check all of the values... 04324 // 1) There is a service name 04325 // 2) If there is a class guid, it is of the proper length 04326 // 04327 if (!ServiceName->Buffer || !ServiceName->Length || 04328 (ClassGuid->Length && (ClassGuid->Length < 38 * sizeof (WCHAR)))) { 04329 goto FreeStrings; 04330 } 04331 04332 // 04333 // Caller expects XxxFilters->Buffer == NULL, so make 04334 // the default case look like that 04335 // 04336 if (UpperFilters->Length <= 2 && UpperFilters->Buffer) { 04337 RtlFreeUnicodeString(UpperFilters); 04338 } 04339 if (LowerFilters->Length <= 2 && LowerFilters->Buffer) { 04340 RtlFreeUnicodeString(LowerFilters); 04341 } 04342 if (ClassGuid->Length == 0 && ClassGuid->Buffer) { 04343 RtlFreeUnicodeString(ClassGuid); 04344 } 04345 04346 #if DBG 04347 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: ***** Using ServiceName %wZ.\n", 04348 ServiceName)); 04349 04350 if (ClassGuid->Buffer) { 04351 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: ***** Using ClassGuid %wZ.\n", 04352 ClassGuid)); 04353 } 04354 #endif 04355 04356 } else { 04357 FreeStrings: 04358 // 04359 // Free any strings that may have been allocated by 04360 // RtlQueryRegistryValues 04361 // 04362 RtlFreeUnicodeString(ServiceName); 04363 RtlFreeUnicodeString(ClassGuid); 04364 RtlFreeUnicodeString(LowerFilters); 04365 RtlFreeUnicodeString(UpperFilters); 04366 } 04367 04368 if (ServiceName->Buffer != NULL) { 04369 *FoundMatch = TRUE; 04370 goto exit; 04371 } 04372 } 04373 04374 // 04375 // See if we're at the end of the MULTI_SZ 04376 // 04377 if (((ptr + 1) == bufferEnd) || !*(ptr + 1)) { 04378 break; 04379 } else { 04380 stringStart = ptr + 1; 04381 } 04382 04383 } 04384 // 04385 // advance to next character. 04386 // 04387 ptr++; 04388 } 04389 } 04390 // 04391 // enumerate next key value. 04392 // 04393 enumIndex++; 04394 } 04395 04396 04397 // 04398 // No match found, and no more values to enumerate. 04399 // 04400 if (status == STATUS_NO_MORE_ENTRIES) { 04401 DebugPrint(1, ("IopProcessCriticalDeviceRoutine: No match found for this device.\n")); 04402 } 04403 04404 04405 exit: 04406 status = STATUS_SUCCESS; 04407 04408 cleanup: 04409 if (infoBuffer.Buffer) { 04410 IopFreeBuffer(&infoBuffer); 04411 } 04412 if (hCriticalDeviceKey) { 04413 ZwClose(hCriticalDeviceKey); 04414 } 04415 if (keyValueInfo[0]) { 04416 ExFreePool(keyValueInfo[0]); 04417 } 04418 if (keyValueInfo[1]) { 04419 ExFreePool(keyValueInfo[1]); 04420 } 04421 return status; 04422 } 04423 04424 USHORT 04425 IopGetBusTypeGuidIndex( 04426 IN LPGUID BusTypeGuid 04427 ) 04428 04429 /*++ 04430 04431 Routine Description: 04432 04433 This routine returns an index into the global table of bus type guids for 04434 guid specified. If this guid is not already in the table, then it will be 04435 added and the index for the new table entry will be returned. This index 04436 is later used by IoGetDeviceProperty to retrieve and return the bus type 04437 guid back to callers but allows us not to bother storing the entire guid 04438 in each devnode (just once per guid in the table). 04439 04440 Arguments: 04441 04442 BusTypeGuid - specifies the guid to retrieve an index for 04443 04444 Return Value: 04445 04446 The index (into the IopBusTypeGuidList table) for the specified guid. 04447 04448 --*/ 04449 04450 { 04451 PCHAR p; 04452 USHORT i, busTypeIndex = 0xffff; // unreported 04453 ULONG size; 04454 04455 ASSERT(IopBusTypeGuidList != NULL); 04456 04457 ExAcquireFastMutex(&IopBusTypeGuidList->Lock); 04458 04459 // 04460 // Search the guid list for a match 04461 // 04462 for (i = 0; i < (USHORT)IopBusTypeGuidList->Count; i++) { 04463 if (IopCompareGuid(BusTypeGuid, &IopBusTypeGuidList->Guid[i])) { 04464 busTypeIndex = i; 04465 goto Clean0; 04466 } 04467 } 04468 04469 // 04470 // Bus type guid doesn't exist in the list. 04471 // 04472 04473 if (IopBusTypeGuidList->Count > 0) { 04474 04475 // 04476 // Reallocate to hold one more guid. 04477 // 04478 04479 size = sizeof(BUS_TYPE_GUID_LIST) + 04480 sizeof(GUID) * (IopBusTypeGuidList->Count); 04481 04482 p = ExAllocatePool(PagedPool, size); 04483 if (!p) { 04484 goto Clean0; // oops, no more room, return unreported 04485 } 04486 04487 size = sizeof(BUS_TYPE_GUID_LIST) + 04488 sizeof(GUID) * (IopBusTypeGuidList->Count - 1); 04489 04490 RtlCopyMemory(p, IopBusTypeGuidList, size); 04491 04492 ExFreePool(IopBusTypeGuidList); 04493 IopBusTypeGuidList = (PBUS_TYPE_GUID_LIST)p; 04494 } 04495 04496 // 04497 // Add the new guid to the list. 04498 // 04499 RtlCopyMemory(&IopBusTypeGuidList->Guid[IopBusTypeGuidList->Count], 04500 BusTypeGuid, 04501 sizeof(GUID)); 04502 04503 busTypeIndex = (USHORT)IopBusTypeGuidList->Count; 04504 IopBusTypeGuidList->Count += 1; 04505 04506 Clean0: 04507 04508 ExReleaseFastMutex(&IopBusTypeGuidList->Lock); 04509 04510 return busTypeIndex; 04511 } 04512 04513 BOOLEAN 04514 IopFixupDeviceId( 04515 PWCHAR DeviceId 04516 ) 04517 04518 /*++ 04519 04520 Routine Description: 04521 04522 This routine parses the device instance string and replaces any invalid 04523 characters (not allowed in a "device instance") with an underscore 04524 character. 04525 04526 Invalid characters are: 04527 c <= 0x20 (' ') 04528 c > 0x7F 04529 c == 0x2C (',') 04530 04531 Arguments: 04532 04533 DeviceId - specifies a device instance string (or part of one), must be 04534 null-terminated. 04535 04536 Return Value: 04537 04538 None. 04539 04540 --*/ 04541 04542 { 04543 PWCHAR p; 04544 04545 // BUGBUG - do we need to uppercase these!? 04546 04547 for (p = DeviceId; *p; p++) { 04548 if (*p == L' ') { 04549 *p = L'_'; 04550 } else if ((*p < L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) { 04551 return FALSE; 04552 } 04553 } 04554 04555 return TRUE; 04556 } 04557 04558 BOOLEAN 04559 IopFixupIds( 04560 IN PWCHAR Ids, 04561 IN ULONG Length 04562 ) 04563 04564 /*++ 04565 04566 Routine Description: 04567 04568 This routine parses multiple IDs and replaces any invalid 04569 characters (not allowed in a "device instance") with an underscore 04570 character. 04571 04572 Invalid characters are: 04573 c <= 0x20 (' ') 04574 c > 0x7F 04575 c == 0x2C (',') 04576 04577 Arguments: 04578 04579 Ids - specifies MULTI_SZ ids. 04580 04581 Length - Specifies the lenght of Ids 04582 04583 Return Value: 04584 04585 None. 04586 04587 --*/ 04588 04589 { 04590 PWCHAR p, end; 04591 04592 p = Ids; 04593 end = p + Length / sizeof(WCHAR); 04594 04595 while ((p < end) && (*p)) { 04596 if (!IopFixupDeviceId(p)) { 04597 return FALSE; 04598 } 04599 04600 while (*p) { 04601 p++; 04602 } 04603 p++; 04604 } 04605 return TRUE; 04606 } 04607 04608 04609 BOOLEAN 04610 IopGetRegistryDwordWithFallback( 04611 IN PUNICODE_STRING valueName, 04612 IN HANDLE PrimaryKey, 04613 IN HANDLE SecondaryKey, 04614 IN OUT PULONG Value) 04615 /*++ 04616 04617 Routine Description: 04618 04619 If 04620 (1) Primary key has a value named "ValueName" that is REG_DWORD, return it 04621 Else If 04622 (2) Secondary key has a value named "ValueName" that is REG_DWORD, return it 04623 Else 04624 (3) Leave Value untouched and return error 04625 04626 Arguments: 04627 04628 ValueName - Unicode name of value to query 04629 PrimaryKey - If non-null, check this first 04630 SecondaryKey - If non-null, check this second 04631 Value - IN = default value, OUT = actual value 04632 04633 Return Value: 04634 04635 TRUE if value found 04636 04637 --*/ 04638 { 04639 PKEY_VALUE_FULL_INFORMATION info; 04640 PUCHAR data; 04641 NTSTATUS status; 04642 HANDLE Keys[3]; 04643 int count = 0; 04644 int index; 04645 BOOLEAN set = FALSE; 04646 04647 if (PrimaryKey != NULL) { 04648 Keys[count++] = PrimaryKey; 04649 } 04650 if (SecondaryKey != NULL) { 04651 Keys[count++] = SecondaryKey; 04652 } 04653 Keys[count] = NULL; 04654 04655 for (index = 0; index < count && !set; index ++) { 04656 info = NULL; 04657 try { 04658 status = IopGetRegistryValue(Keys[index], 04659 valueName->Buffer, 04660 &info); 04661 if (NT_SUCCESS(status) && info->Type == REG_DWORD) { 04662 data = ((PUCHAR) info) + info->DataOffset; 04663 *Value = *((PULONG) data); 04664 set = TRUE; 04665 } 04666 } except(EXCEPTION_EXECUTE_HANDLER) { 04667 // 04668 // do nothing 04669 // 04670 } 04671 if (info) { 04672 ExFreePool(info); 04673 } 04674 } 04675 return set; 04676 } 04677 04678 PSECURITY_DESCRIPTOR 04679 IopGetRegistrySecurityWithFallback( 04680 IN PUNICODE_STRING valueName, 04681 IN HANDLE PrimaryKey, 04682 IN HANDLE SecondaryKey) 04683 /*++ 04684 04685 Routine Description: 04686 04687 If 04688 (1) Primary key has a binary value named "ValueName" that is 04689 REG_BINARY and appears to be a valid security descriptor, return it 04690 Else 04691 (2) do same for Secondary key 04692 Else 04693 (3) Return NULL 04694 04695 Arguments: 04696 04697 ValueName - Unicode name of value to query 04698 PrimaryKey - If non-null, check this first 04699 SecondaryKey - If non-null, check this second 04700 04701 Return Value: 04702 04703 Security Descriptor if found, else NULL 04704 04705 --*/ 04706 { 04707 PKEY_VALUE_FULL_INFORMATION info; 04708 PUCHAR data; 04709 NTSTATUS status; 04710 HANDLE Keys[3]; 04711 int count = 0; 04712 int index; 04713 BOOLEAN set = FALSE; 04714 PSECURITY_DESCRIPTOR secDesc = NULL; 04715 PSECURITY_DESCRIPTOR allocDesc = NULL; 04716 04717 if (PrimaryKey != NULL) { 04718 Keys[count++] = PrimaryKey; 04719 } 04720 if (SecondaryKey != NULL) { 04721 Keys[count++] = SecondaryKey; 04722 } 04723 Keys[count] = NULL; 04724 04725 for (index = 0; index < count && !set; index ++) { 04726 info = NULL; 04727 try { 04728 status = IopGetRegistryValue(Keys[index], 04729 valueName->Buffer, 04730 &info); 04731 if (NT_SUCCESS(status) && info->Type == REG_BINARY) { 04732 data = ((PUCHAR) info) + info->DataOffset; 04733 secDesc = (PSECURITY_DESCRIPTOR)data; 04734 status = SeCaptureSecurityDescriptor(secDesc, 04735 KernelMode, 04736 PagedPool, 04737 TRUE, 04738 &allocDesc); 04739 if (NT_SUCCESS(status)) { 04740 set = TRUE; 04741 } 04742 } 04743 } except(EXCEPTION_EXECUTE_HANDLER) { 04744 // 04745 // do nothing 04746 // 04747 } 04748 if (info) { 04749 ExFreePool(info); 04750 } 04751 } 04752 if (set) { 04753 return allocDesc; 04754 } 04755 return NULL; 04756 } 04757 04758 NTSTATUS 04759 IopChangeDeviceObjectFromRegistryProperties( 04760 IN PDEVICE_OBJECT PhysicalDeviceObject, 04761 IN HANDLE DeviceClassPropKey, 04762 IN HANDLE DevicePropKey, 04763 IN BOOLEAN UsePdoCharacteristics 04764 ) 04765 /*++ 04766 04767 Routine Description: 04768 04769 This routine will obtain settings from either 04770 (1) DevNode settings (via DevicePropKey) or 04771 (2) Class settings (via DeviceClassPropKey) 04772 applying to PDO and all attached device objects 04773 04774 Properties set/ changed are: 04775 04776 * DeviceType - the I/O system type for the device object 04777 * DeviceCharacteristics - the I/O system characteristic flags to be 04778 set for the device object 04779 * Exclusive - the device can only be accessed exclusively 04780 * Security - security for the device 04781 04782 The routine will then use the DeviceType and DeviceCharacteristics specified 04783 to determine whether a VPB should be allocated as well as to set default 04784 security if none is specified in the registry. 04785 04786 Arguments: 04787 04788 PhysicalDeviceObject - the PDO we are to configure 04789 04790 DeviceClassPropKey - a handle to Control<Class>\Properties protected key 04791 DevicePropKey - a handle to Enum<Instance> protected key 04792 04793 Return Value: 04794 04795 status 04796 04797 --*/ 04798 04799 { 04800 UNICODE_STRING valueName; 04801 PKEY_VALUE_FULL_INFORMATION info; 04802 PUCHAR data; 04803 NTSTATUS status; 04804 04805 BOOLEAN deviceTypeSpec = FALSE; 04806 BOOLEAN characteristicsSpec = FALSE; 04807 BOOLEAN exclusiveSpec = FALSE; 04808 BOOLEAN securityForce = FALSE; 04809 CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; 04810 SECURITY_INFORMATION securityInformation = 0; 04811 04812 PSECURITY_DESCRIPTOR securityDescriptor = NULL; 04813 PACL allocatedAcl = NULL; 04814 ULONG deviceType = 0; 04815 ULONG characteristics = 0; 04816 ULONG exclusive = 0; 04817 ULONG prevCharacteristics = 0; 04818 ULONG prevExclusive = 0; 04819 PDEVICE_OBJECT StackIterator = NULL; 04820 PDEVICE_NODE deviceNode = NULL; 04821 04822 ASSERT(PhysicalDeviceObject); 04823 deviceNode = PhysicalDeviceObject->DeviceObjectExtension->DeviceNode; 04824 ASSERT(deviceNode); 04825 04826 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Modifying device stack for PDO: %08x\n",PhysicalDeviceObject)); 04827 04828 // 04829 // Iterate through all device objects to get our starting settings (OR everyone together) 04830 // generally, a PDO should take on the characteristics of whoever is above the PDO, and not used in the equation 04831 // the exception being if it's being used RAW 04832 // we detect this by absense of service name, or it's the only Device Object. 04833 // 04834 StackIterator = PhysicalDeviceObject; 04835 if (UsePdoCharacteristics || StackIterator->AttachedDevice == NULL) { 04836 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Assuming PDO is being used RAW\n")); 04837 } else { 04838 StackIterator = StackIterator->AttachedDevice; 04839 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Ignoring PDO's settings\n")); 04840 } 04841 for ( ; StackIterator != NULL; StackIterator = StackIterator->AttachedDevice) { 04842 #if 0 // BUGBUG (jamiehun) we were breaking serial, I'd like to put this back in though... 04843 prevExclusive |= StackIterator->Flags & DO_EXCLUSIVE; 04844 #endif 04845 prevCharacteristics |= StackIterator->Characteristics; 04846 } 04847 04848 // 04849 // 1) Get Device type, DevicePropKey preferred over DeviceClassPropKey 04850 // 04851 RtlInitUnicodeString(&valueName, REGSTR_VAL_DEVICE_TYPE); 04852 deviceTypeSpec = IopGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&deviceType); 04853 RtlInitUnicodeString(&valueName, REGSTR_VAL_DEVICE_CHARACTERISTICS); 04854 characteristicsSpec = IopGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&characteristics); 04855 RtlInitUnicodeString(&valueName, REGSTR_VAL_DEVICE_EXCLUSIVE); 04856 exclusiveSpec = IopGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&exclusive); 04857 04858 if (exclusive) { 04859 // 04860 // make sure a TRUE maps to a bit-mask 04861 // 04862 exclusive = DO_EXCLUSIVE; 04863 } 04864 04865 if (exclusiveSpec) { 04866 exclusive |= prevExclusive; 04867 } else { 04868 exclusive = prevExclusive; 04869 } 04870 if (!characteristicsSpec) { 04871 characteristics = 0; 04872 } 04873 characteristics = (characteristics | prevCharacteristics) & FILE_CHARACTERISTICS_PROPAGATED; // mask only applicable characteristics 04874 04875 RtlInitUnicodeString(&valueName, REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR); 04876 securityDescriptor = IopGetRegistrySecurityWithFallback(&valueName,DevicePropKey,DeviceClassPropKey); 04877 04878 if (securityDescriptor == NULL) { 04879 // 04880 // determine if we should create internal default 04881 // 04882 if (deviceTypeSpec) { 04883 BOOLEAN hasName = (PhysicalDeviceObject->Flags & DO_DEVICE_HAS_NAME) ? TRUE : FALSE; 04884 04885 securityDescriptor = IopCreateDefaultDeviceSecurityDescriptor( 04886 (DEVICE_TYPE)deviceType, 04887 characteristics, 04888 hasName, 04889 buffer, 04890 &allocatedAcl, 04891 &securityInformation 04892 ); 04893 if (securityDescriptor) { 04894 securityForce = TRUE; // forced default security descriptor 04895 } else { 04896 DebugPrint(1, ("IopChangeDeviceObjectFromRegistryProperties: Was not able to get default security descriptor\n")); 04897 } 04898 } 04899 } else { 04900 // 04901 // further process the security information we're given to set "securityInformation" 04902 // 04903 PSID sid; 04904 PACL acl; 04905 BOOLEAN present, tmp; 04906 04907 securityInformation = 0; 04908 04909 // 04910 // See what information is in the captured descriptor so we can build 04911 // up a securityInformation block to go with it. 04912 // 04913 04914 status = RtlGetOwnerSecurityDescriptor(securityDescriptor, &sid, &tmp); 04915 04916 if (NT_SUCCESS(status) && (sid != NULL)) { 04917 securityInformation |= OWNER_SECURITY_INFORMATION; 04918 } 04919 04920 status = RtlGetGroupSecurityDescriptor(securityDescriptor, &sid, &tmp); 04921 04922 if (NT_SUCCESS(status) && (sid != NULL)) { 04923 securityInformation |= GROUP_SECURITY_INFORMATION; 04924 } 04925 04926 status = RtlGetSaclSecurityDescriptor(securityDescriptor, 04927 &present, 04928 &acl, 04929 &tmp); 04930 04931 if (NT_SUCCESS(status) && (present)) { 04932 securityInformation |= SACL_SECURITY_INFORMATION; 04933 } 04934 04935 status = RtlGetDaclSecurityDescriptor(securityDescriptor, 04936 &present, 04937 &acl, 04938 &tmp); 04939 04940 if (NT_SUCCESS(status) && (present)) { 04941 securityInformation |= DACL_SECURITY_INFORMATION; 04942 } 04943 04944 } 04945 04946 #if DBG 04947 if (deviceTypeSpec == FALSE && characteristicsSpec == FALSE && exclusiveSpec == FALSE && securityDescriptor == NULL) { 04948 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: No property changes\n")); 04949 } else { 04950 if (deviceTypeSpec) { 04951 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Overide DeviceType=%08x\n", 04952 deviceType)); 04953 } 04954 if (characteristicsSpec) { 04955 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Overide DeviceCharacteristics=%08x\n", 04956 characteristics)); 04957 } 04958 if (exclusiveSpec) { 04959 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Overide Exclusive=%d\n",(exclusive?1:0))); 04960 } 04961 if (securityForce) { 04962 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Overide Security based on DeviceType & DeviceCharacteristics\n")); 04963 } 04964 if (securityDescriptor == NULL) { 04965 DebugPrint(2, ("IopChangeDeviceObjectFromRegistryProperties: Overide Security\n")); 04966 } 04967 } 04968 #endif 04969 // 04970 // modify apropriate characteristics of PDO to be the same as those of rest of stack 04971 // eg, PDO may be initialized as Raw-Capable Secure Open, but then be modified to be more lax 04972 // 04973 PhysicalDeviceObject->Characteristics = (PhysicalDeviceObject->Characteristics & ~FILE_CHARACTERISTICS_PROPAGATED) | characteristics; 04974 ASSERT((PhysicalDeviceObject->Characteristics & FILE_CHARACTERISTICS_PROPAGATED) == characteristics); // sanity (checks bit bounds) 04975 // 04976 // modify exclusivity of PDO to be the same as those of rest of stack 04977 // eg, PDO may be initialized as Exclusive open, but be modified to be more lax 04978 // 04979 #if 0 // BUGBUG (jamiehun) we were breaking serial, I'd like to put this back in though... 04980 PhysicalDeviceObject->Flags = (PhysicalDeviceObject->Flags & ~DO_EXCLUSIVE) | exclusive; 04981 ASSERT((PhysicalDeviceObject->Flags & DO_EXCLUSIVE) == exclusive); // sanity (checks bit bounds) 04982 #endif 04983 04984 // 04985 // iterate through rest of objects 04986 // these flags were used to create characteristics & deviceType, so 04987 // we will only end up setting flags, not clearing them 04988 // 04989 for ( StackIterator = PhysicalDeviceObject->AttachedDevice ; StackIterator != NULL ; StackIterator = StackIterator->AttachedDevice) { 04990 // 04991 // modify characteristics (set only) 04992 // 04993 StackIterator->Characteristics |= characteristics; 04994 ASSERT((StackIterator->Characteristics & FILE_CHARACTERISTICS_PROPAGATED) == characteristics); // sanity (checks we only needed to set) 04995 // 04996 // modify exclusivity flag (set only) 04997 // 04998 StackIterator->Flags |= exclusive; 04999 #if 0 // BUGBUG (jamiehun) we were breaking serial, I'd like to put this back in though... 05000 ASSERT((StackIterator->Flags & DO_EXCLUSIVE) == exclusive); // sanity (checks we only needed to set) 05001 #endif 05002 } 05003 if (deviceTypeSpec) { 05004 // 05005 // modify device type - PDO only 05006 // 05007 PhysicalDeviceObject->DeviceType = deviceType; 05008 } 05009 if (securityDescriptor != NULL) { 05010 // 05011 // modify security (applied to whole stack) 05012 // 05013 status = ObSetSecurityObjectByPointer(PhysicalDeviceObject, 05014 securityInformation, 05015 securityDescriptor); 05016 if (NT_SUCCESS(status) == FALSE) { 05017 DebugPrint(1, ("IopChangeDeviceObjectFromRegistryProperties: Set security failed (%08x)\n",status)); 05018 } 05019 } 05020 // 05021 // cleanup 05022 // 05023 if ((securityDescriptor != NULL) && !securityForce) { 05024 ExFreePool(securityDescriptor); 05025 } 05026 if (allocatedAcl) { 05027 ExFreePool(allocatedAcl); 05028 } 05029 05030 return STATUS_SUCCESS; 05031 } 05032 05033 NTSTATUS 05034 IopProcessNewProfile( 05035 VOID 05036 ) 05037 05038 /*++ 05039 05040 Routine Description: 05041 05042 This function is called after the system has transitioned into a new 05043 hardware profile. The thread from which it is called may be holding an 05044 enumeration lock. Calling this function does two tasks: 05045 05046 1) If a disabled devnode in the tree should be enabled in this new hardware 05047 profile state, it will be started. 05048 05049 2) If an enabled devnode in the tree should be disabled in this new hardware 05050 profile state, it will be (surprise) removed. 05051 05052 ADRIAO N.B. 02/19/1999 - 05053 Why surprise remove? There are four cases to be handled: 05054 a) Dock disappearing, need to enable device in new profile 05055 b) Dock appearing, need to enable device in new profile 05056 c) Dock disappearing, need to disable device in new profile 05057 d) Dock appearing, need to disable device in new profile 05058 05059 a) and b) are trivial. c) involves treating the appropriate devices as 05060 if they were in the removal relation lists for the dock. d) is another 05061 matter altogether as we need to query-remove/remove devices before 05062 starting another. NT5's PnP state machine cannot handle this, so for 05063 this release we cleanup rather hastily after the profile change. 05064 05065 Parameters: 05066 05067 NONE. 05068 05069 Return Value: 05070 05071 NTSTATUS. 05072 05073 --*/ 05074 { 05075 PWORK_QUEUE_ITEM workQueueItem; 05076 05077 PAGED_CODE(); 05078 05079 workQueueItem = (PWORK_QUEUE_ITEM) ExAllocatePool( 05080 NonPagedPool, 05081 sizeof(WORK_QUEUE_ITEM) 05082 ); 05083 05084 if (workQueueItem) { 05085 05086 // 05087 // Queue this up so we can walk the tree outside of the enumeration lock. 05088 // 05089 ExInitializeWorkItem( 05090 workQueueItem, 05091 IopProcessNewProfileWorker, 05092 workQueueItem 05093 ); 05094 05095 ExQueueWorkItem( 05096 workQueueItem, 05097 CriticalWorkQueue 05098 ); 05099 05100 return STATUS_SUCCESS; 05101 05102 } else { 05103 05104 return STATUS_INSUFFICIENT_RESOURCES; 05105 } 05106 } 05107 05108 VOID 05109 IopProcessNewProfileWorker( 05110 IN PVOID Context 05111 ) 05112 05113 /*++ 05114 05115 Routine Description: 05116 05117 This function is called for each devnode after the system has transitioned 05118 to a new hardware profile. 05119 05120 Parameters: 05121 05122 NONE. 05123 05124 Return Value: 05125 05126 NONE. 05127 05128 --*/ 05129 { 05130 PAGED_CODE(); 05131 05132 IopForAllDeviceNodes(IopProcessNewProfileStateCallback, NULL); 05133 05134 ExFreePool(Context); 05135 } 05136 05137 NTSTATUS 05138 IopProcessNewProfileStateCallback( 05139 IN PDEVICE_NODE DeviceNode, 05140 IN PVOID Context 05141 ) 05142 05143 /*++ 05144 05145 Routine Description: 05146 05147 This function is called for each devnode after the system has transitioned 05148 hardware profile states. 05149 05150 Parameters: 05151 05152 NONE. 05153 05154 Return Value: 05155 05156 NONE. 05157 05158 --*/ 05159 { 05160 PDEVICE_NODE parentDevNode; 05161 05162 PAGED_CODE(); 05163 05164 if (DeviceNode->Flags & DNF_STARTED) { 05165 05166 // 05167 // Calling this function will disable the device if it is appropriate 05168 // to do so. 05169 // 05170 if (!IopIsDeviceInstanceEnabled(NULL, &DeviceNode->InstancePath, FALSE)) { 05171 05172 IopRequestDeviceRemoval( 05173 DeviceNode->PhysicalDeviceObject, 05174 CM_PROB_DISABLED 05175 ); 05176 } 05177 05178 } else if (IopIsDevNodeProblem(DeviceNode, CM_PROB_DISABLED)) { 05179 05180 // 05181 // We might be turning on the device. So we will clear the problem 05182 // flags iff the device problem was CM_PROB_DISABLED. 05183 // 05184 IopClearDevNodeProblem(DeviceNode); 05185 05186 // 05187 // Make sure the device stays down iff appropriate. 05188 // 05189 if (IopIsDeviceInstanceEnabled(NULL, &DeviceNode->InstancePath, FALSE)) { 05190 05191 // 05192 // This device should come back online. Queue up an enumeration 05193 // at the parent level for him. 05194 // 05195 parentDevNode = DeviceNode->Parent; 05196 05197 IoInvalidateDeviceRelations( 05198 parentDevNode->PhysicalDeviceObject, 05199 BusRelations 05200 ); 05201 } 05202 } 05203 05204 return STATUS_SUCCESS; 05205 }

Generated on Sat May 15 19:41:16 2004 for test by doxygen 1.3.7