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

dockhwp.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1998 Microsoft Corporation 00004 00005 Module Name: 00006 00007 dock.c 00008 00009 Abstract: 00010 00011 00012 Author: 00013 00014 Kenneth D. Ray (kenray) Feb 1998 00015 00016 Revision History: 00017 00018 --*/ 00019 00020 #include "iop.h" 00021 #undef ExAllocatePool 00022 #undef ExAllocatePoolWithQuota 00023 #include "..\config\cmp.h" 00024 #include <string.h> 00025 #include <profiles.h> 00026 #include <wdmguid.h> 00027 00028 #if DBG 00029 00030 #define ASSERT_SEMA_NOT_SIGNALLED(SemaphoreObject) \ 00031 ASSERT(KeReadStateSemaphore(SemaphoreObject) == 0) ; 00032 00033 #else // DBG 00034 00035 #define ASSERT_SEMA_NOT_SIGNALLED(SemaphoreObject) 00036 00037 #endif // DBG 00038 00039 // 00040 // Internal functions to dockhwp.c 00041 // 00042 00043 NTSTATUS 00044 IopExecuteHardwareProfileChange( 00045 IN HARDWARE_PROFILE_BUS_TYPE Bus, 00046 IN PWCHAR * ProfileSerialNumbers, 00047 IN ULONG SerialNumbersCount, 00048 OUT PHANDLE NewProfile, 00049 OUT PBOOLEAN ProfileChanged 00050 ); 00051 00052 NTSTATUS 00053 IopUpdateHardwareProfile ( 00054 OUT PBOOLEAN ProfileChanged 00055 ); 00056 00057 VOID 00058 IopHardwareProfileSendCommit( 00059 VOID 00060 ); 00061 00062 VOID 00063 IopHardwareProfileSendCancel( 00064 VOID 00065 ); 00066 00067 // 00068 // List of current dock devices, and the number of dockdevices. 00069 // Must hold IopDockDeviceListLock to change these values. 00070 // 00071 LIST_ENTRY IopDockDeviceListHead; 00072 ULONG IopDockDeviceCount; 00073 FAST_MUTEX IopDockDeviceListLock; 00074 KSEMAPHORE IopProfileChangeSemaphore; 00075 BOOLEAN IopProfileChangeCancelRequired; 00076 LONG IopDocksInTransition; 00077 00078 typedef struct { 00079 00080 WORK_QUEUE_ITEM WorkItem; 00081 KEVENT NotificationCompleted ; 00082 LPGUID NotificationGuid ; 00083 NTSTATUS FinalStatus ; 00084 PPNP_VETO_TYPE VetoType ; 00085 PUNICODE_STRING VetoName ; 00086 00087 } PROFILE_WORK_ITEM, *PPROFILE_WORK_ITEM ; 00088 00089 #ifdef ALLOC_PRAGMA 00090 #pragma alloc_text(PAGE, IopHardwareProfileBeginTransition) 00091 #pragma alloc_text(PAGE, IopHardwareProfileMarkDock) 00092 #pragma alloc_text(PAGE, IopHardwareProfileQueryChange) 00093 #pragma alloc_text(PAGE, IopHardwareProfileCommitStartedDock) 00094 #pragma alloc_text(PAGE, IopHardwareProfileCommitRemovedDock) 00095 #pragma alloc_text(PAGE, IopHardwareProfileCancelRemovedDock) 00096 #pragma alloc_text(PAGE, IopHardwareProfileCancelTransition) 00097 #define alloc_text(PAGE, IopHardwareProfileSendCommit) 00098 #pragma alloc_text(PAGE, IopHardwareProfileSendCancel) 00099 #endif // ALLOC_PRAGMA 00100 00101 00102 VOID 00103 IopHardwareProfileBeginTransition( 00104 IN BOOLEAN SubsumeExistingDeparture 00105 ) 00106 /*++ 00107 00108 Routine Description: 00109 00110 This routine must be called before any dock devnodes can be marked for 00111 transition (ie arriving or departing). After calling this function, 00112 IopHardwareProfileMarkDock should be called for each dock that is appearing 00113 or disappearing. 00114 00115 Functionally, this code acquires the profile change semaphore. Future 00116 changes in the life of the added dock devnodes cause it to be released. 00117 00118 Arguments: 00119 00120 SubsumeExistingDeparture - Set if we are ejecting the parent of a 00121 device that is still in the process of 00122 ejecting... 00123 00124 Return Value: 00125 00126 None. 00127 00128 --*/ 00129 { 00130 NTSTATUS status ; 00131 00132 if (SubsumeExistingDeparture) { 00133 00134 // 00135 // We will already have queried in this case. Also, enumeration is 00136 // locked right now, so the appropriate devices found cannot disappear. 00137 // Assert everything is consistant. 00138 // 00139 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00140 ASSERT(IopDocksInTransition != 0) ; 00141 return ; 00142 } 00143 00144 // 00145 // Take the profile change semaphore. We do this whenever a dock is 00146 // in our list, even if no query is going to occur. 00147 // 00148 status = KeWaitForSingleObject( 00149 &IopProfileChangeSemaphore, 00150 Executive, 00151 KernelMode, 00152 FALSE, 00153 NULL 00154 ); 00155 00156 ASSERT(status == STATUS_SUCCESS) ; 00157 } 00158 00159 VOID 00160 IopHardwareProfileMarkDock( 00161 PDEVICE_NODE DeviceNode, 00162 PROFILE_STATUS ChangeInPresence 00163 ) 00164 /*++ 00165 00166 Routine Description: 00167 00168 This routine is called to mark a dock as "in transition", ie it is either 00169 disappearing or appearing, the results of which determine our final 00170 hardware profile state. After all the docks that are transitioning have 00171 been passed into this function, IopHardwareProfileQueryChange is called. 00172 00173 Arguments: 00174 00175 DeviceNode - The dock devnode that is appearing or disappearing 00176 ChangeInPresence - Either DOCK_DEPARTING or DOCK_ARRIVING 00177 00178 Return Value: 00179 00180 Nope. 00181 00182 --*/ 00183 { 00184 PWCHAR deviceSerialNumber; 00185 PDEVICE_OBJECT deviceObject; 00186 NTSTATUS status; 00187 00188 // 00189 // Verify we are under semaphore, we aren't marking the dock twice, and 00190 // our parameters are sensable. 00191 // 00192 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00193 ASSERT(DeviceNode->DockInfo.DockStatus == DOCK_QUIESCENT) ; 00194 ASSERT((ChangeInPresence == DOCK_DEPARTING)|| 00195 (ChangeInPresence == DOCK_ARRIVING)) ; 00196 00197 if (ChangeInPresence == DOCK_ARRIVING) { 00198 00199 // 00200 // First, ensure this dock is a member of the dock list. 00201 // ADRIAO BUGBUG 11/12/98 - 00202 // We should move this into IopProcessNewDeviceNode. 00203 // 00204 if (IsListEmpty(&DeviceNode->DockInfo.ListEntry)) { 00205 00206 // 00207 // Acquire the lock on the list of dock devices 00208 // 00209 ExAcquireFastMutex(&IopDockDeviceListLock); 00210 00211 // 00212 // Add this element to the head of the list 00213 // 00214 InsertHeadList(&IopDockDeviceListHead, 00215 &DeviceNode->DockInfo.ListEntry); 00216 IopDockDeviceCount++; 00217 00218 // 00219 // Release the lock on the list of dock devices 00220 // 00221 ExReleaseFastMutex(&IopDockDeviceListLock); 00222 } 00223 00224 // 00225 // Retrieve the Serial Number from this dock device. We do this just 00226 // to test the BIOS today. Later we will be acquiring the information 00227 // to determine the profile we are *about* to enter. 00228 // 00229 deviceObject = DeviceNode->PhysicalDeviceObject; 00230 status = IopQueryDeviceSerialNumber(deviceObject, 00231 &deviceSerialNumber); 00232 00233 if (NT_SUCCESS(status) && (deviceSerialNumber != NULL)) { 00234 00235 ExFreePool(deviceSerialNumber) ; 00236 } 00237 00238 } else { 00239 00240 // 00241 // DOCK_DEPARTING case, we must be a member of the dock list... 00242 // 00243 ASSERT(!IsListEmpty(&DeviceNode->DockInfo.ListEntry)) ; 00244 } 00245 00246 InterlockedIncrement(&IopDocksInTransition) ; 00247 DeviceNode->DockInfo.DockStatus = ChangeInPresence ; 00248 } 00249 00250 NTSTATUS 00251 IopHardwareProfileQueryChange( 00252 IN BOOLEAN SubsumingExistingDeparture, 00253 IN PROFILE_NOTIFICATION_TIME InPnpEvent, 00254 OUT PPNP_VETO_TYPE VetoType, 00255 OUT PUNICODE_STRING VetoName OPTIONAL 00256 ) 00257 /*++ 00258 00259 Routine Description: 00260 00261 This function queries drivers to see if it is OK to exit the current 00262 hardware profile and enter next one (as determined by which docks have 00263 been marked). One of three functions should be used subsequently to this 00264 call: 00265 IopHardwareProfileCommitStartedDock (call when a dock has successfully 00266 started) 00267 IopHardwareProfileCommitRemovedDock (call when a dock is no longer 00268 present in the system) 00269 IopHardwareProfileCancelTransition (call to abort a transition, say 00270 if a dock failed to start or a 00271 query returned failure for eject) 00272 00273 Arguments: 00274 00275 InPnpEvent - This argument indicates whether an operation is being done 00276 within the context of another PnpEvent or not. If not, we 00277 will queue such an event and block on it. If so, we cannot 00278 queue&block (we'd deadlock), so we do the query manually. 00279 VetoType - If this function returns false, this parameter will describe 00280 who failed the query profile change. The below optional 00281 parameter will contain the name of said vetoer. 00282 VetoName - This optional parameter will get the name of the vetoer (ie 00283 devinst, service name, application name, etc). If VetoName 00284 is supplied, the caller must free the buffer returned. 00285 00286 Return Value: 00287 00288 NTSTATUS. 00289 00290 --*/ 00291 { 00292 PROFILE_WORK_ITEM profileWorkItem; 00293 NTSTATUS status; 00294 BOOLEAN arrivingDockFound; 00295 PLIST_ENTRY listEntry ; 00296 PDEVICE_NODE devNode ; 00297 00298 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00299 00300 // 00301 // Acquire the lock on the list of dock devices and determine whether any 00302 // dock devnodes are arriving. 00303 // 00304 ExAcquireFastMutex(&IopDockDeviceListLock); 00305 00306 ASSERT(IopDocksInTransition) ; 00307 00308 arrivingDockFound = FALSE ; 00309 for (listEntry = IopDockDeviceListHead.Flink; 00310 listEntry != &(IopDockDeviceListHead); 00311 listEntry = listEntry->Flink ) { 00312 00313 devNode = CONTAINING_RECORD(listEntry, 00314 DEVICE_NODE, 00315 DockInfo.ListEntry); 00316 00317 ASSERT((devNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE)&& 00318 (devNode->DockInfo.DockStatus != DOCK_EJECTIRP_COMPLETED)) ; 00319 00320 if (devNode->DockInfo.DockStatus == DOCK_ARRIVING) { 00321 00322 arrivingDockFound = TRUE ; 00323 } 00324 } 00325 00326 // 00327 // Release the lock on the list of dock devices 00328 // 00329 ExReleaseFastMutex(&IopDockDeviceListLock); 00330 00331 if (SubsumingExistingDeparture) { 00332 00333 ASSERT(IopProfileChangeCancelRequired) ; 00334 // 00335 // We're nesting. Work off the last query, and don't requery. 00336 // 00337 return STATUS_SUCCESS ; 00338 } 00339 00340 if (arrivingDockFound) { 00341 00342 // 00343 // We currently don't actually query for hardware profile change on a 00344 // dock event as the user may have the lid closed. If we ever find a 00345 // piece of hardware that needs to be updated *prior* to actually 00346 // switching over, we will have to remove this bit of code. 00347 // 00348 IopProfileChangeCancelRequired = FALSE ; 00349 return STATUS_SUCCESS ; 00350 } 00351 00352 PIDBGMSG(PIDBG_HWPROFILE, ("NTOSKRNL: Sending HW profile change [query]\n")) ; 00353 00354 status = IopRequestHwProfileChangeNotification( 00355 (LPGUID) &GUID_HWPROFILE_QUERY_CHANGE, 00356 InPnpEvent, 00357 VetoType, 00358 VetoName 00359 ); 00360 00361 if (NT_SUCCESS(status)) { 00362 IopProfileChangeCancelRequired = TRUE ; 00363 } else { 00364 IopProfileChangeCancelRequired = FALSE ; 00365 } 00366 return status ; 00367 } 00368 00369 VOID 00370 IopHardwareProfileCommitStartedDock( 00371 IN PDEVICE_NODE DeviceNode 00372 ) 00373 /*++ 00374 00375 Routine Description: 00376 00377 This routine adds the specified device from the list of current dock 00378 devices and requests a Hardware Profile change. 00379 00380 Arguments: 00381 00382 DeviceNode - Supplies a pointer to a device node which will be started and 00383 enumerated. 00384 00385 Return Value: 00386 00387 None. 00388 00389 --*/ 00390 { 00391 NTSTATUS status; 00392 PDEVICE_OBJECT deviceObject; 00393 PWCHAR deviceSerialNumber; 00394 BOOLEAN profileChanged = FALSE ; 00395 00396 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00397 ASSERT(DeviceNode->DockInfo.DockStatus == DOCK_ARRIVING) ; 00398 ASSERT(!IsListEmpty(&DeviceNode->DockInfo.ListEntry)) ; 00399 00400 DeviceNode->DockInfo.DockStatus = DOCK_QUIESCENT ; 00401 InterlockedDecrement(&IopDocksInTransition) ; 00402 00403 // 00404 // We only add one dock at a time. So this should have been the last! 00405 // 00406 ASSERT(!IopDocksInTransition) ; 00407 00408 // 00409 // Retrieve the Serial Number from this dock device 00410 // 00411 if (DeviceNode->DockInfo.SerialNumber == NULL) { 00412 00413 deviceObject = DeviceNode->PhysicalDeviceObject; 00414 00415 status = IopQueryDeviceSerialNumber(deviceObject, 00416 &deviceSerialNumber); 00417 00418 DeviceNode->DockInfo.SerialNumber = deviceSerialNumber; 00419 00420 // 00421 // Update the current Hardware Profile after successfully starting this 00422 // device. This routine does two things for us: 00423 // 1) It determines whether the profile actually changed and updates 00424 // the global flag IopProfileChangeOccured appropriately. 00425 // 2) If the profile changed, this routine updates the registry, but 00426 // does *not* broadcast the profile change around. 00427 // 00428 status = IopUpdateHardwareProfile(&profileChanged); 00429 if (!NT_SUCCESS(status)) { 00430 00431 PIDBGMSG( 00432 PIDBG_HWPROFILE, 00433 ("IopUpdateHardwareProfile failed with status == %lx\n", status) 00434 ) ; 00435 } 00436 00437 } else { 00438 // 00439 // Couldn't get Serial Number for this dock device, or serial number was NULL 00440 // 00441 status = STATUS_UNSUCCESSFUL; 00442 } 00443 00444 if (NT_SUCCESS(status) && profileChanged) { 00445 00446 IopHardwareProfileSendCommit() ; 00447 IopProcessNewProfile(); 00448 00449 } else if (IopProfileChangeCancelRequired) { 00450 00451 IopHardwareProfileSendCancel() ; 00452 } 00453 00454 KeReleaseSemaphore( 00455 &IopProfileChangeSemaphore, 00456 IO_NO_INCREMENT, 00457 1, 00458 FALSE 00459 ); 00460 00461 return ; 00462 } 00463 00464 VOID 00465 IopHardwareProfileCommitRemovedDock( 00466 IN PDEVICE_NODE DeviceNode 00467 ) 00468 /*++ 00469 00470 Routine Description: 00471 00472 This routine removes the specified device from the list of current dock 00473 devices and requests a Hardware Profile change. 00474 00475 Arguments: 00476 00477 DeviceNode - Supplies a pointer to a device node which has been listed as 00478 missing in a previous enumeration, has had the final remove IRP 00479 sent to it, and is about to be deleted. 00480 00481 Return Value: 00482 00483 None. 00484 00485 --*/ 00486 { 00487 NTSTATUS status; 00488 BOOLEAN profileChanged ; 00489 LONG remainingDockCount ; 00490 00491 // 00492 // Acquire the lock on the list of dock devices 00493 // 00494 ExAcquireFastMutex(&IopDockDeviceListLock); 00495 00496 // 00497 // Since we are about to remove this dock device from the list of 00498 // all dock devices present, the list should not be empty. 00499 // 00500 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00501 ASSERT((DeviceNode->DockInfo.DockStatus == DOCK_DEPARTING)|| 00502 (DeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED)) ; 00503 ASSERT(!IsListEmpty(&DeviceNode->DockInfo.ListEntry)) ; 00504 00505 // 00506 // Remove the current devnode from the list of docks 00507 // 00508 RemoveEntryList(&DeviceNode->DockInfo.ListEntry); 00509 InitializeListHead(&DeviceNode->DockInfo.ListEntry); 00510 if (DeviceNode->DockInfo.SerialNumber) { 00511 00512 ExFreePool(DeviceNode->DockInfo.SerialNumber); 00513 DeviceNode->DockInfo.SerialNumber = NULL; 00514 } 00515 IopDockDeviceCount--; 00516 00517 DeviceNode->DockInfo.DockStatus = DOCK_QUIESCENT ; 00518 remainingDockCount = InterlockedDecrement(&IopDocksInTransition) ; 00519 ASSERT(remainingDockCount >= 0) ; 00520 00521 // 00522 // Release the lock on the list of dock devices 00523 // 00524 ExReleaseFastMutex(&IopDockDeviceListLock); 00525 00526 if (remainingDockCount) { 00527 00528 return ; 00529 } 00530 00531 // 00532 // Update the current Hardware Profile after removing this device. 00533 // 00534 status = IopUpdateHardwareProfile(&profileChanged); 00535 00536 if (!NT_SUCCESS(status)) { 00537 00538 // 00539 // So we're there physically, but not mentally? Too bad, where broadcasting 00540 // change either way. 00541 // 00542 PIDBGMSG( 00543 PIDBG_HWPROFILE, 00544 ("IopUpdateHardwareProfile failed with status == %lx\n", status) 00545 ) ; 00546 00547 ASSERT(NT_SUCCESS(status)) ; 00548 } 00549 00550 if (NT_SUCCESS(status) && profileChanged) { 00551 00552 IopHardwareProfileSendCommit() ; 00553 IopProcessNewProfile(); 00554 00555 } else { 00556 00557 ASSERT(IopProfileChangeCancelRequired) ; 00558 IopHardwareProfileSendCancel() ; 00559 } 00560 00561 KeReleaseSemaphore( 00562 &IopProfileChangeSemaphore, 00563 IO_NO_INCREMENT, 00564 1, 00565 FALSE 00566 ); 00567 00568 return ; 00569 } 00570 00571 VOID 00572 IopHardwareProfileCancelRemovedDock( 00573 IN PDEVICE_NODE DeviceNode 00574 ) 00575 /*++ 00576 00577 Routine Description: 00578 00579 This routine is called when a dock that was marked to disappear didn't (ie, 00580 after the eject, the dock device still enumerated). We remove it from the 00581 transition list and complete/cancel the HW profile change as appropriate. 00582 See IopHardwareProfileSetMarkedDocksEjected. 00583 00584 Arguments: 00585 00586 DeviceNode - Supplies a pointer to a device node which will be started and 00587 enumerated. 00588 00589 Return Value: 00590 00591 None. 00592 00593 --*/ 00594 { 00595 NTSTATUS status; 00596 BOOLEAN profileChanged ; 00597 LONG remainingDockCount ; 00598 00599 // 00600 // Acquire the lock on the list of dock devices 00601 // 00602 ExAcquireFastMutex(&IopDockDeviceListLock); 00603 00604 // 00605 // Since we are about to remove this dock device from the list of 00606 // all dock devices present, the list should not be empty. 00607 // 00608 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00609 ASSERT(DeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED) ; 00610 ASSERT(!IsListEmpty(&DeviceNode->DockInfo.ListEntry)) ; 00611 00612 DeviceNode->DockInfo.DockStatus = DOCK_QUIESCENT ; 00613 remainingDockCount = InterlockedDecrement(&IopDocksInTransition) ; 00614 ASSERT(remainingDockCount >= 0) ; 00615 00616 // 00617 // Release the lock on the list of dock devices 00618 // 00619 ExReleaseFastMutex(&IopDockDeviceListLock); 00620 00621 if (remainingDockCount) { 00622 00623 return ; 00624 } 00625 00626 // 00627 // Update the current Hardware Profile after removing this device. 00628 // 00629 status = IopUpdateHardwareProfile(&profileChanged); 00630 00631 if (!NT_SUCCESS(status)) { 00632 00633 // 00634 // So we're there physically, but not mentally? Too bad, where broadcasting 00635 // change either way. 00636 // 00637 PIDBGMSG( 00638 PIDBG_HWPROFILE, 00639 ("IopUpdateHardwareProfile failed with status == %lx\n", status) 00640 ) ; 00641 ASSERT(NT_SUCCESS(status)) ; 00642 } 00643 00644 if (NT_SUCCESS(status) && profileChanged) { 00645 00646 IopHardwareProfileSendCommit() ; 00647 IopProcessNewProfile(); 00648 00649 } else { 00650 00651 ASSERT(IopProfileChangeCancelRequired) ; 00652 IopHardwareProfileSendCancel() ; 00653 } 00654 00655 KeReleaseSemaphore( 00656 &IopProfileChangeSemaphore, 00657 IO_NO_INCREMENT, 00658 1, 00659 FALSE 00660 ); 00661 00662 return ; 00663 } 00664 00665 VOID 00666 IopHardwareProfileCancelTransition( 00667 VOID 00668 ) 00669 /*++ 00670 00671 Routine Description: 00672 00673 This routine unmarks any marked devnodes (ie, sets them to no change, 00674 appearing or disappearing), and sends the CancelQueryProfileChange as 00675 appropriate. Once called, other profile changes can occur. 00676 00677 Arguments: 00678 00679 None. 00680 00681 Return Value: 00682 00683 Nodda. 00684 00685 --*/ 00686 { 00687 PLIST_ENTRY listEntry; 00688 PDEVICE_NODE devNode; 00689 00690 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00691 00692 // 00693 // Acquire the lock on the list of dock devices 00694 // 00695 ExAcquireFastMutex(&IopDockDeviceListLock); 00696 00697 for (listEntry = IopDockDeviceListHead.Flink; 00698 listEntry != &(IopDockDeviceListHead); 00699 listEntry = listEntry->Flink ) { 00700 00701 devNode = CONTAINING_RECORD(listEntry, 00702 DEVICE_NODE, 00703 DockInfo.ListEntry); 00704 00705 ASSERT((devNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE)&& 00706 (devNode->DockInfo.DockStatus != DOCK_EJECTIRP_COMPLETED)) ; 00707 if (devNode->DockInfo.DockStatus != DOCK_QUIESCENT) { 00708 00709 InterlockedDecrement(&IopDocksInTransition) ; 00710 devNode->DockInfo.DockStatus = DOCK_QUIESCENT ; 00711 } 00712 } 00713 00714 ASSERT(!IopDocksInTransition) ; 00715 00716 // 00717 // Release the lock on the list of dock devices 00718 // 00719 ExReleaseFastMutex(&IopDockDeviceListLock); 00720 00721 if (IopProfileChangeCancelRequired) { 00722 00723 IopHardwareProfileSendCancel() ; 00724 } 00725 00726 // 00727 // No need to broadcast the cancels here, as IopQueryHardwareProfileChange 00728 // will have taken care of the cancels for us. 00729 // 00730 KeReleaseSemaphore( 00731 &IopProfileChangeSemaphore, 00732 IO_NO_INCREMENT, 00733 1, 00734 FALSE 00735 ); 00736 } 00737 00738 VOID 00739 IopHardwareProfileSetMarkedDocksEjected( 00740 VOID 00741 ) 00742 /*++ 00743 00744 Routine Description: 00745 00746 This routine moves any departing devnodes to the ejected state. If any 00747 subsequent enumeration lists the device as present, we know the eject 00748 failed and we appropriately cancel that piece of the profile change. 00749 IopHardwareProfileCancelRemovedDock can only be called after this function 00750 is called. 00751 00752 Arguments: 00753 00754 None. 00755 00756 Return Value: 00757 00758 Nodda. 00759 00760 --*/ 00761 { 00762 PLIST_ENTRY listEntry; 00763 PDEVICE_NODE devNode; 00764 00765 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00766 00767 // 00768 // Acquire the lock on the list of dock devices 00769 // 00770 ExAcquireFastMutex(&IopDockDeviceListLock); 00771 00772 for (listEntry = IopDockDeviceListHead.Flink; 00773 listEntry != &(IopDockDeviceListHead); 00774 listEntry = listEntry->Flink ) { 00775 00776 devNode = CONTAINING_RECORD(listEntry, 00777 DEVICE_NODE, 00778 DockInfo.ListEntry); 00779 00780 ASSERT((devNode->DockInfo.DockStatus == DOCK_QUIESCENT)|| 00781 (devNode->DockInfo.DockStatus == DOCK_DEPARTING)) ; 00782 if (devNode->DockInfo.DockStatus != DOCK_QUIESCENT) { 00783 00784 devNode->DockInfo.DockStatus = DOCK_EJECTIRP_COMPLETED ; 00785 } 00786 } 00787 00788 // 00789 // Release the lock on the list of dock devices 00790 // 00791 ExReleaseFastMutex(&IopDockDeviceListLock); 00792 } 00793 00794 VOID 00795 IopHardwareProfileSendCommit( 00796 VOID 00797 ) 00798 /*++ 00799 00800 Routine Description: 00801 00802 This routine (internal to dockhwp.c) simply sends the change complete message. 00803 We do not wait for this, as it is asynchronous... 00804 00805 Arguments: 00806 00807 None. 00808 00809 Return Value: 00810 00811 Nodda. 00812 00813 --*/ 00814 { 00815 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00816 PIDBGMSG(PIDBG_HWPROFILE, ("NTOSKRNL: Sending HW profile change [commit]\n")) ; 00817 00818 IopRequestHwProfileChangeNotification( 00819 (LPGUID) &GUID_HWPROFILE_CHANGE_COMPLETE, 00820 PROFILE_PERHAPS_IN_PNPEVENT, 00821 NULL, 00822 NULL 00823 ); 00824 } 00825 00826 VOID 00827 IopHardwareProfileSendCancel( 00828 VOID 00829 ) 00830 /*++ 00831 00832 Routine Description: 00833 00834 This routine (internal to dockhwp.c) simply sends the cancel. 00835 00836 Arguments: 00837 00838 None. 00839 00840 Return Value: 00841 00842 Nodda. 00843 00844 --*/ 00845 { 00846 PROFILE_WORK_ITEM profileWorkItem; 00847 PNP_VETO_TYPE vetoType; 00848 NTSTATUS status; 00849 00850 ASSERT_SEMA_NOT_SIGNALLED(&IopProfileChangeSemaphore) ; 00851 PIDBGMSG(PIDBG_HWPROFILE, ("NTOSKRNL: Sending HW profile change [cancel]\n")) ; 00852 00853 IopRequestHwProfileChangeNotification( 00854 (LPGUID) &GUID_HWPROFILE_CHANGE_CANCELLED, 00855 PROFILE_PERHAPS_IN_PNPEVENT, 00856 NULL, 00857 NULL 00858 ) ; 00859 } 00860 00861 NTSTATUS 00862 IopUpdateHardwareProfile ( 00863 OUT PBOOLEAN ProfileChanged 00864 ) 00865 /*++ 00866 Routine Description: 00867 00868 This routine scans the list of current dock devices, builds a list of serial 00869 numbers from those devices, and calls for the Hardware Profile to be 00870 changed, based on that list. 00871 00872 Arguments: 00873 00874 ProfileChanged - Supplies a variable to receive TRUE if the current hardware 00875 profile changes as a result of calling this routine. 00876 00877 Return Value: 00878 00879 NTSTATUS code. 00880 00881 --*/ 00882 { 00883 NTSTATUS status = STATUS_SUCCESS; 00884 PLIST_ENTRY listEntry; 00885 PDEVICE_NODE devNode; 00886 PWCHAR *profileSerialNumbers, *p; 00887 HANDLE hProfileKey=NULL; 00888 ULONG len, numProfiles; 00889 HANDLE hCurrent, hIDConfigDB; 00890 UNICODE_STRING unicodeName; 00891 00892 // 00893 // Acquire the lock on the list of dock devices 00894 // 00895 ExAcquireFastMutex(&IopDockDeviceListLock); 00896 00897 // 00898 // Update the flag for Ejectable Docks 00899 // 00900 RtlInitUnicodeString(&unicodeName, CM_HARDWARE_PROFILE_STR_DATABASE); 00901 if(NT_SUCCESS(IopOpenRegistryKey(&hIDConfigDB, 00902 NULL, 00903 &unicodeName, 00904 KEY_READ, 00905 FALSE) )) { 00906 00907 RtlInitUnicodeString(&unicodeName, CM_HARDWARE_PROFILE_STR_CURRENT_DOCK_INFO); 00908 if(NT_SUCCESS(IopOpenRegistryKey(&hCurrent, 00909 hIDConfigDB, 00910 &unicodeName, 00911 KEY_READ | KEY_WRITE, 00912 FALSE) )) { 00913 00914 RtlInitUnicodeString(&unicodeName, REGSTR_VAL_EJECTABLE_DOCKS); 00915 ZwSetValueKey(hCurrent, 00916 &unicodeName, 00917 0, 00918 REG_DWORD, 00919 &IopDockDeviceCount, 00920 sizeof(IopDockDeviceCount)); 00921 ZwClose(hCurrent); 00922 } 00923 ZwClose(hIDConfigDB); 00924 } 00925 00926 if (IopDockDeviceCount == 0) { 00927 // 00928 // if there are no dock devices, the list should 00929 // contain a single null entry, in addition to the null 00930 // termination. 00931 // 00932 numProfiles = 1; 00933 ASSERT(IsListEmpty(&IopDockDeviceListHead)); 00934 } else { 00935 numProfiles = IopDockDeviceCount; 00936 ASSERT(!IsListEmpty(&IopDockDeviceListHead)); 00937 } 00938 00939 // 00940 // Allocate space for a null-terminated list of SerialNumber lists. 00941 // 00942 len = (numProfiles+1)*sizeof(PWCHAR); 00943 profileSerialNumbers = ExAllocatePool(NonPagedPool, len); 00944 00945 if (profileSerialNumbers) { 00946 00947 p = profileSerialNumbers; 00948 00949 // 00950 // Create the list of Serial Numbers 00951 // 00952 for (listEntry = IopDockDeviceListHead.Flink; 00953 listEntry != &(IopDockDeviceListHead); 00954 listEntry = listEntry->Flink ) { 00955 00956 devNode = CONTAINING_RECORD(listEntry, 00957 DEVICE_NODE, 00958 DockInfo.ListEntry); 00959 00960 // 00961 // ADRIAO BUGBUG 11/11/98 - 00962 // Is everything in the quiescent state here? 00963 // 00964 ASSERT(devNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE) ; 00965 if (devNode->DockInfo.SerialNumber) { 00966 *p = devNode->DockInfo.SerialNumber; 00967 p++; 00968 } 00969 } 00970 00971 ExReleaseFastMutex(&IopDockDeviceListLock); 00972 00973 if (p == profileSerialNumbers) { 00974 // 00975 // Set a single list entry to NULL if we look to be in an "undocked" 00976 // profile 00977 // 00978 *p = NULL; 00979 p++; 00980 } 00981 00982 // 00983 // Null-terminate the list 00984 // 00985 *p = NULL; 00986 00987 numProfiles = (ULONG)(p - profileSerialNumbers); 00988 00989 // 00990 // Change the current Hardware Profile based on the new Dock State 00991 // and perform notification that the Hardware Profile has changed 00992 // 00993 status = IopExecuteHardwareProfileChange(HardwareProfileBusTypeACPI, 00994 profileSerialNumbers, 00995 numProfiles, 00996 &hProfileKey, 00997 ProfileChanged); 00998 if (hProfileKey) { 00999 ZwClose(hProfileKey); 01000 } 01001 ExFreePool (profileSerialNumbers); 01002 01003 } else { 01004 01005 ExReleaseFastMutex(&IopDockDeviceListLock); 01006 01007 status = STATUS_INSUFFICIENT_RESOURCES; 01008 } 01009 01010 return status; 01011 } 01012 01013 NTSTATUS 01014 IopExecuteHwpDefaultSelect ( 01015 IN PCM_HARDWARE_PROFILE_LIST ProfileList, 01016 OUT PULONG ProfileIndexToUse, 01017 IN PVOID Context 01018 ) 01019 { 01020 UNREFERENCED_PARAMETER (Context); 01021 01022 * ProfileIndexToUse = 0; 01023 01024 return STATUS_SUCCESS; 01025 } 01026 01027 NTSTATUS 01028 IopExecuteHardwareProfileChange( 01029 IN HARDWARE_PROFILE_BUS_TYPE Bus, 01030 IN PWCHAR * ProfileSerialNumbers, 01031 IN ULONG SerialNumbersCount, 01032 OUT PHANDLE NewProfile, 01033 OUT PBOOLEAN ProfileChanged 01034 ) 01035 01036 01037 /*++ 01038 Routine Description: 01039 A docking event has occured and now, given a list of Profile Serial Numbers 01040 that describe the new docking state: 01041 Transition to the given docking state. 01042 Set the Current Hardware Profile to based on the new state. 01043 (Possibly Prompt the user if there is ambiguity) 01044 Send Removes to those devices that are turned off in this profile, 01045 01046 Arguments: 01047 Bus - This is the bus that is supplying the hardware profile change 01048 (currently only HardwareProfileBusTypeAcpi is supported). 01049 01050 ProfileSerialNumbers - A list of serial numbers (a list of null terminated 01051 UCHAR lists) representing this new docking state. These can be listed in 01052 any order, and form a complete representation of the new docking state 01053 caused by a docking even on the given bus. A Serial Number string of "\0" 01054 represents an "undocked state" and should not be listed with any other 01055 strings. This list need not be sorted. 01056 01057 SerialNumbersCount - The number of serial numbers listed. 01058 01059 NewProfile - a handle to the registry key representing the new hardware 01060 profile (IE \CCS\HardwareProfiles\Current".) 01061 01062 ProfileChanged - set to TRUE if new current profile (as a result of this 01063 docking event, is different that then old current profile. 01064 01065 --*/ 01066 { 01067 NTSTATUS status = STATUS_SUCCESS; 01068 ULONG len; 01069 ULONG tmplen; 01070 ULONG i, j; 01071 PWCHAR tmpStr; 01072 UNICODE_STRING tmpUStr; 01073 PUNICODE_STRING sortedSerials = NULL; 01074 01075 PPROFILE_ACPI_DOCKING_STATE dockState = NULL; 01076 01077 PIDBGMSG( 01078 PIDBG_HWPROFILE, 01079 ("Execute Profile (BusType %x), (SerialNumCount %x)\n", Bus, SerialNumbersCount) 01080 ) ; 01081 01082 // 01083 // Sort the list of serial numbers 01084 // 01085 len = sizeof (UNICODE_STRING) * SerialNumbersCount; 01086 sortedSerials = ExAllocatePool (NonPagedPool, len); 01087 if (NULL == sortedSerials) { 01088 status = STATUS_INSUFFICIENT_RESOURCES; 01089 goto Clean; 01090 } 01091 for (i = 0; i < SerialNumbersCount; i++) { 01092 RtlInitUnicodeString (&sortedSerials[i], ProfileSerialNumbers[i]); 01093 } 01094 // 01095 // I do not anticipate getting more than a few serial numbers, and I am 01096 // just lasy enough to write this comment and use a buble sort. 01097 // 01098 for (i = 0; i < SerialNumbersCount; i++) { 01099 for (j = 0; j < SerialNumbersCount - 1; j++) { 01100 if (0 < RtlCompareUnicodeString (&sortedSerials[j], 01101 &sortedSerials[j+1], 01102 FALSE)) { 01103 tmpUStr = sortedSerials[j]; 01104 sortedSerials[j] = sortedSerials[j+1]; 01105 sortedSerials[j+1] = tmpUStr; 01106 } 01107 } 01108 } 01109 01110 // 01111 // Construct the DockState ID 01112 // 01113 len = 0; 01114 for (i = 0; i < SerialNumbersCount; i++) { 01115 len += sortedSerials[i].Length; 01116 } 01117 len += sizeof (WCHAR); // NULL termination; 01118 01119 dockState = (PPROFILE_ACPI_DOCKING_STATE) 01120 ExAllocatePool (NonPagedPool, 01121 len + sizeof (PROFILE_ACPI_DOCKING_STATE)); 01122 // BUGBUG wasted WCHAR here. Oh well. 01123 01124 if (NULL == dockState) { 01125 status = STATUS_INSUFFICIENT_RESOURCES; 01126 goto Clean; 01127 } 01128 for (i = 0, tmpStr = dockState->SerialNumber, tmplen = 0; 01129 i < SerialNumbersCount; 01130 i++) { 01131 01132 tmplen = sortedSerials[i].Length; 01133 ASSERT (tmplen <= len - ((PCHAR)tmpStr - (PCHAR)dockState->SerialNumber)); 01134 01135 RtlCopyMemory (tmpStr, sortedSerials[i].Buffer, tmplen); 01136 (PCHAR) tmpStr += tmplen; 01137 } 01138 01139 *(tmpStr++) = L'\0'; 01140 01141 ASSERT (len == (ULONG) ((PCHAR) tmpStr - (PCHAR) dockState->SerialNumber)); 01142 dockState->SerialLength = (USHORT) len; 01143 01144 if ((SerialNumbersCount > 1) || (L'\0' != dockState->SerialNumber[0])) { 01145 dockState->DockingState = HW_PROFILE_DOCKSTATE_DOCKED; 01146 } else { 01147 dockState->DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED; 01148 } 01149 01150 01151 // 01152 // Set the new Profile 01153 // 01154 switch (Bus) { 01155 case HardwareProfileBusTypeACPI: 01156 01157 status = CmSetAcpiHwProfile (dockState, 01158 IopExecuteHwpDefaultSelect, 01159 NULL, 01160 NewProfile, 01161 ProfileChanged); 01162 01163 ASSERT(NT_SUCCESS(status) || (!(*ProfileChanged))) ; 01164 break; 01165 01166 default: 01167 *ProfileChanged = FALSE ; 01168 status = STATUS_NOT_SUPPORTED; 01169 goto Clean; 01170 } 01171 01172 Clean: 01173 if (NULL != sortedSerials) { 01174 ExFreePool (sortedSerials); 01175 } 01176 if (NULL != dockState) { 01177 ExFreePool (dockState); 01178 } 01179 01180 return status; 01181 } 01182 01183 01184 01185 // 01186 // Beyond here lie commented out code. This code is a sketch of what we will 01187 // use when we do two-step profile changes (ie, using the serial numbers figure 01188 // out what profile we are *about* to enter, and return a set of all existing 01189 // profiles that we might transition into. Today this code is not used as not 01190 // all BIOS's can tell us what profile we are entering prior to being there. 01191 // 01192 01193 #if 0 01194 01195 struct _IOP_NEW_ACPI_STATE { 01196 ULONG Blah; 01197 PCM_HARDWARE_PROFILE_LIST ProfileList; 01198 01199 } IOP_NEW_ACPI_STATE, *PIOP_NEW_ACPI_STATE; 01200 01201 01202 NTSTATUS 01203 IopProfileAcquisition ( 01204 IN PCM_HARDWARE_PROFILE_LIST ProfileList, 01205 OUT PULONG ProfileIndexToUse, 01206 IN PIOP_PROFILE_LIST NewAcpiState 01207 ) 01208 /*++ 01209 Routine Description 01210 01211 --*/ 01212 { 01213 PCM_HARDWARE_PROFILE_LIST tmpList; 01214 NTSTATUS status = STATUS_SUCCESS; 01215 ULONG i; 01216 ULONG k; 01217 ULONG oldSize; 01218 ULONG newSize; 01219 BOOLEAN found; 01220 01221 // 01222 // We need to add the entries from ProfileList to our new acpi state 01223 // 01224 // Use the most inefficient manner possible to see if we already have 01225 // this profile. Hopefully there will not be that many profiles around. 01226 // 01227 ASSERT (ProfileList->CurrentProfileCount <= ProfileList->MaxProfileCount); 01228 for (i = 0; i < ProfileList->CurrentProfileCount; i++) { 01229 found = FALSE; 01230 01231 for (k = 0; k < NewAcpiState->ProfileList->CurrentProfileCount; k++) { 01232 if (ProfileList->Profile[i].Id == 01233 NewAcpiState->ProfileList->Profile[k]) { 01234 found = TRUE; 01235 break; 01236 } 01237 } 01238 01239 if (!found) { 01240 // 01241 // Add it 01242 // 01243 if (NewAcpiState->MaxProfileCount <= NewAcpiState->CurrentProfileCount) { 01244 tmpList = NewAcpiState->ProfileList; 01245 01246 oldSize = sizeof (CM_HARDWARE_PROFILE_LIST) 01247 + (sizeof (CM_HARDWARE_PROFILE) * 01248 (tmpList->MaxProfileCount - 1)); 01249 01250 newSize = tmpList->MaxProfileCount * 2; 01251 newSize = sizeof (CM_HARDWARE_PROFILE_LIST) 01252 + (sizeof (CM_HAREWARE_PROFILE) * (newSize - 1)); 01253 01254 tmpList = ExAllocatePool (PagedPool, newSize); 01255 if (NULL == tmpList) { 01256 return STATUS_INSUFFICIENT_RESOURCES; 01257 } 01258 RtlCopyMemory (tmpList, NewAcpiState->ProfileList, oldSize); 01259 // NB current count and Max count copied over as well 01260 tmpList->MaxProfileCount *= 2; 01261 01262 ExFreePool (NewAcpiState->ProfileList); 01263 NewAcpiState->ProfileList = tmpList; 01264 } 01265 01266 k = NewAcpiState->ProfileList->CurrentProfileCount++; 01267 NewAcpiState->ProfileList->Profile[k] = ProfileList->Profile[i]. 01268 } 01269 01270 } 01271 01272 01273 01274 *ProfileIndexToUse = -1; // Don't select anything yet. 01275 return status; 01276 } 01277 01278 01279 NTSTATUS 01280 IopFindPossibleProfiles ( 01281 IN PPROFILE_ACPI_DOCKING_STATE * AcpiProfiles, 01282 IN ULONG PossibleDockingStates, 01283 OUT PCM_HARDWARE_PROFILE_LIST * ProfileList 01284 ) 01285 /*++ 01286 Routine Description: 01287 Based on the cononical list of possible acpi docking states, determine the 01288 cononical list of Hardware profiles that might result. 01289 01290 Arguments: 01291 AcpiProfiles - A list of pointers to AcpiProfiles that could be achieved 01292 in the next docking state. 01293 01294 PossibleDockingStates - The total number of AcpiProfiles. 01295 01296 ProfileList - the cononical list of hardware profiles that could result from 01297 the given list of acpi docking profiles. 01298 01299 --*/ 01300 { 01301 NTSTATUS status = STATUS_SUCCESS; 01302 ULONG i; 01303 IOP_PROFILE_CONTEXT context; 01304 PROFILE_ACPI_DOCKING_STATE acpiDockState; 01305 01306 context->ProfileList = ExAllocatePool (NonPagedPool, 01307 sizeof (PCM_HARDWARE_PROFILE_LIST)); 01308 if (NULL == context->ProfileList) { 01309 status = STATUS_INSUFICIENT_RESOURCES; 01310 goto Clean; 01311 } 01312 context->ProfileList->MaxProfileCount = 1; 01313 context->ProfileList->CurrentProfileCount = 0; 01314 01315 for (i = 0; i < PossibleDockingStates; i++) { 01316 01317 status = CmSetAcpiHwProfile (AcpiProfiles[i], 01318 IopProfileAcquisition, 01319 &context); 01320 01321 if (STATUS_MORE_PROCESSING_REQUIRED == status) { 01322 status = STATUS_SUCCESS; 01323 } 01324 if (!NT_SUCCESS (status)) { 01325 goto Clean; 01326 } 01327 } 01328 status = STATUS_SUCCESS 01329 01330 *ProfileList = context->ProfileList; 01331 01332 Clean: 01333 01334 if (NULL != context->ProfileList) { 01335 ExFreePool (context->ProfileList); 01336 } 01337 01338 if (!NT_SUCCESS(status)) { 01339 if (possibleProfileList) { 01340 ExFreePool (possibleProfileList); 01341 } 01342 } 01343 01344 return status; 01345 } 01346 01347 typedef struct _IOP_ACPI_DOCKING_PROFILE_INFO { 01348 ULONG Blah; 01349 } IOP_ACPI_DOCKING_PROFILE_INFO, * PIOP_ACPI_DOCKING_PROFILE_INFO; 01350 01351 NTSTATUS 01352 IopAcpiQueryDockingProfileEvent ( 01353 IN PUCHAR * AcpiDockSerialNumbers, 01354 IN ULONG PossibleSerialNumbers, 01355 IN PFOOBAR DockRelations, 01356 OUT PIOP_ACPI_DOCKING_PROFILE_INFO * AcpiDockInfo, 01357 ) 01358 /*++ 01359 Routine Description: 01360 Given a list of ACPI serial numbers that might appear once an ACPI docking 01361 event has completed, determine the cononical list of hardware profiles that 01362 could result from the docking serial numbers provided. Query remove all 01363 devices listed as disabled across all of these profiles. If all queries 01364 succeed, then remove all devices. If not cancel the queries. 01365 01366 Return success iff all query removes completed successfully. Otherwise 01367 fail. 01368 01369 Do not actually cause the remove of these devices. 01370 01371 01372 Arguments 01373 AcpiDockSerialNumbers - a list of serial numbers for the possible docks 01374 that may be attached for this acpi docking event. 01375 01376 PossibleSerialNumbers - number of elements in that list. 01377 01378 BUGBUG 01379 DockRelations - the list of (help me out here I don't really know) which 01380 may be removed when this docking state is executed. 01381 BUGBUG 01382 01383 01384 AcpiDockInfo - a context parameter that needs to be passed to 01385 IopAcpiExecuteDockingProfile. 01386 01387 --*/ 01388 { 01389 NTSTATUS status = STATUS_SUCCESS; 01390 01391 return status; 01392 } 01393 01394 #endif 01395 01396

Generated on Sat May 15 19:39:46 2004 for test by doxygen 1.3.7