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

hwprofil.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1998 Microsoft Corporation 00004 00005 Module Name: 00006 00007 hwprofil.c 00008 00009 Abstract: 00010 00011 This module contains support for changing the Hardware profile 00012 based on the current docking state, either at boot time or by 00013 ACPI dock. 00014 00015 Author: 00016 00017 Kenneth D. Ray (kenray) Jan 1998 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include "cmp.h" 00024 00025 NTSTATUS 00026 CmDeleteKeyRecursive( 00027 HANDLE hKeyRoot, 00028 PWSTR Key, 00029 PVOID TemporaryBuffer, 00030 ULONG LengthTemporaryBuffer, 00031 BOOLEAN ThisKeyToo 00032 ); 00033 00034 NTSTATUS 00035 CmpGetAcpiProfileInformation ( 00036 IN HANDLE IDConfigDB, 00037 OUT PCM_HARDWARE_PROFILE_LIST * ProfileList, 00038 OUT PCM_HARDWARE_PROFILE_ACPI_ALIAS_LIST * AliasList, 00039 IN PWCHAR NameBuffer, 00040 IN PUCHAR ValueBuffer, 00041 IN ULONG Len 00042 ); 00043 00044 NTSTATUS 00045 CmpFilterAcpiDockingState ( 00046 IN PPROFILE_ACPI_DOCKING_STATE NewDockState, 00047 IN ULONG CurrentDockingState, 00048 IN PWCHAR CurrentAcpiSN, 00049 IN ULONG CurrentProfileNumber, 00050 IN OUT PCM_HARDWARE_PROFILE_LIST ProfileList, 00051 IN OUT PCM_HARDWARE_PROFILE_ACPI_ALIAS_LIST AliasList 00052 ); 00053 00054 NTSTATUS 00055 CmpMoveBiosAliasTable ( 00056 IN HANDLE IDConfigDB, 00057 IN HANDLE CurrentInfo, 00058 IN ULONG CurrentProfileNumber, 00059 IN ULONG NewProfileNumber, 00060 IN PWCHAR nameBuffer, 00061 IN PCHAR valueBuffer, 00062 IN ULONG bufferLen 00063 ); 00064 00065 #pragma alloc_text(PAGE,CmpCloneHwProfile) 00066 #pragma alloc_text(PAGE,CmSetAcpiHwProfile) 00067 #pragma alloc_text(PAGE,CmpFilterAcpiDockingState) 00068 #pragma alloc_text(PAGE,CmpGetAcpiProfileInformation) 00069 #pragma alloc_text(PAGE,CmpAddAcpiAliasEntry) 00070 #pragma alloc_text(PAGE,CmpMoveBiosAliasTable) 00071 #pragma alloc_text(PAGE,CmpCreateHwProfileFriendlyName) 00072 00073 extern UNICODE_STRING CmSymbolicLinkValueName; 00074 00075 NTSTATUS 00076 CmpGetAcpiProfileInformation ( 00077 IN HANDLE IDConfigDB, 00078 OUT PCM_HARDWARE_PROFILE_LIST * ProfileList, 00079 OUT PCM_HARDWARE_PROFILE_ACPI_ALIAS_LIST * AliasList, 00080 IN PWCHAR nameBuffer, 00081 IN PUCHAR valueBuffer, 00082 IN ULONG bufferLen 00083 ) 00084 /*++ 00085 Routine Description: 00086 00087 Obtain the alias and hardware profile information from the registry. 00088 00089 --*/ 00090 { 00091 NTSTATUS status = STATUS_SUCCESS; 00092 HANDLE acpiAlias = NULL; 00093 HANDLE profiles = NULL; 00094 HANDLE entry = NULL; 00095 ULONG len = 0; 00096 ULONG i, j; 00097 OBJECT_ATTRIBUTES attributes; 00098 UNICODE_STRING name; 00099 KEY_FULL_INFORMATION keyInfo; 00100 PKEY_VALUE_FULL_INFORMATION value; 00101 PKEY_BASIC_INFORMATION basicInfo; 00102 00103 PAGED_CODE (); 00104 00105 *ProfileList = NULL; 00106 *AliasList = NULL; 00107 00108 value = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 00109 basicInfo = (PKEY_BASIC_INFORMATION) valueBuffer; 00110 00111 // 00112 // Open a handle to the Profile information 00113 // 00114 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_HARDWARE_PROFILES); 00115 InitializeObjectAttributes (&attributes, 00116 &name, 00117 OBJ_CASE_INSENSITIVE, 00118 IDConfigDB, 00119 NULL); 00120 status = ZwOpenKey (&profiles, 00121 KEY_READ, 00122 &attributes); 00123 00124 if (!NT_SUCCESS (status)) { 00125 profiles = NULL; 00126 goto Clean; 00127 } 00128 00129 // 00130 // Find the number of profile Sub Keys 00131 // 00132 status = ZwQueryKey (profiles, 00133 KeyFullInformation, 00134 &keyInfo, 00135 sizeof (keyInfo), 00136 &len); 00137 00138 if (!NT_SUCCESS (status)) { 00139 goto Clean; 00140 } 00141 00142 ASSERT (0 < keyInfo.SubKeys); 00143 00144 len = sizeof (CM_HARDWARE_PROFILE_LIST) 00145 + (sizeof (CM_HARDWARE_PROFILE) * (keyInfo.SubKeys - 1)); 00146 00147 * ProfileList = ExAllocatePool (PagedPool, len); 00148 if (NULL == *ProfileList) { 00149 status = STATUS_INSUFFICIENT_RESOURCES; 00150 goto Clean; 00151 } 00152 RtlZeroMemory (*ProfileList, len); 00153 00154 (*ProfileList)->MaxProfileCount = keyInfo.SubKeys; 00155 (*ProfileList)->CurrentProfileCount = 0; 00156 00157 // 00158 // Iterrate the profiles 00159 // 00160 for (i = 0; i < keyInfo.SubKeys; i++) { 00161 CM_HARDWARE_PROFILE TempProfile; 00162 UNICODE_STRING KeyName; 00163 ULONG realsize; 00164 00165 // 00166 // Get the first key in the list. 00167 // 00168 status = ZwEnumerateKey (profiles, 00169 i, 00170 KeyBasicInformation, 00171 basicInfo, 00172 bufferLen - sizeof (UNICODE_NULL), // term 0 00173 &len); 00174 00175 if (!NT_SUCCESS (status)) { 00176 // 00177 // This should never happen. 00178 // 00179 break; 00180 } 00181 00182 basicInfo->Name [basicInfo->NameLength/sizeof(WCHAR)] = 0; 00183 name.Length = (USHORT) basicInfo->NameLength; 00184 name.MaximumLength = (USHORT) basicInfo->NameLength + sizeof (UNICODE_NULL); 00185 name.Buffer = basicInfo->Name; 00186 00187 InitializeObjectAttributes (&attributes, 00188 &name, 00189 OBJ_CASE_INSENSITIVE, 00190 profiles, 00191 NULL); 00192 status = ZwOpenKey (&entry, 00193 KEY_READ, 00194 &attributes); 00195 if (!NT_SUCCESS (status)) { 00196 break; 00197 } 00198 00199 // 00200 // Fill in the temporary profile structure with this 00201 // profile's data. 00202 // 00203 RtlUnicodeStringToInteger(&name, 0, &TempProfile.Id); 00204 00205 // 00206 // Find the pref order of this entry. 00207 // 00208 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PREFERENCE_ORDER); 00209 status = NtQueryValueKey(entry, 00210 &name, 00211 KeyValueFullInformation, 00212 valueBuffer, 00213 bufferLen, 00214 &len); 00215 00216 if ((!NT_SUCCESS (status)) || (value->Type != REG_DWORD)) { 00217 TempProfile.PreferenceOrder = -1; 00218 00219 } else { 00220 TempProfile.PreferenceOrder 00221 = * (PULONG) ((PUCHAR) value + value->DataOffset); 00222 } 00223 00224 // 00225 // Extract the friendly name 00226 // 00227 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_FRIENDLY_NAME); 00228 status = NtQueryValueKey(entry, 00229 &name, 00230 KeyValueFullInformation, 00231 valueBuffer, 00232 bufferLen, 00233 &len); 00234 00235 if (!NT_SUCCESS (status) || (value->Type != REG_SZ)) { 00236 WCHAR tmpname[] = L"------"; // as taken from cmboot.c 00237 ULONG len; 00238 PVOID buffer; 00239 00240 len = sizeof (tmpname); 00241 buffer = ExAllocatePool (PagedPool, len); 00242 00243 TempProfile.NameLength = len; 00244 TempProfile.FriendlyName = buffer; 00245 if (NULL == buffer) { 00246 status = STATUS_INSUFFICIENT_RESOURCES; 00247 ZwClose (entry); 00248 goto Clean; 00249 } 00250 RtlCopyMemory (buffer, tmpname, value->DataLength); 00251 00252 } else { 00253 PVOID buffer; 00254 00255 buffer = ExAllocatePool (PagedPool, value->DataLength); 00256 TempProfile.NameLength = value->DataLength; 00257 TempProfile.FriendlyName = buffer; 00258 if (NULL == buffer) { 00259 status = STATUS_INSUFFICIENT_RESOURCES; 00260 ZwClose (entry); 00261 goto Clean; 00262 } 00263 RtlCopyMemory (buffer, 00264 (PUCHAR) value + value->DataOffset, 00265 value->DataLength); 00266 } 00267 00268 TempProfile.Flags = 0; 00269 // 00270 // Is this aliasable? 00271 // 00272 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ALIASABLE); 00273 status = NtQueryValueKey(entry, 00274 &name, 00275 KeyValueFullInformation, 00276 valueBuffer, 00277 bufferLen, 00278 &len); 00279 00280 if (NT_SUCCESS (status) && (value->Type == REG_DWORD)) { 00281 if (* (PULONG) ((PUCHAR) value + value->DataOffset)) { 00282 TempProfile.Flags |= CM_HP_FLAGS_ALIASABLE; 00283 } 00284 00285 } else { 00286 TempProfile.Flags |= CM_HP_FLAGS_ALIASABLE; 00287 } 00288 00289 // 00290 // Is this pristine? 00291 // 00292 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PRISTINE); 00293 status = NtQueryValueKey(entry, 00294 &name, 00295 KeyValueFullInformation, 00296 valueBuffer, 00297 bufferLen, 00298 &len); 00299 00300 if (NT_SUCCESS (status) && (value->Type == REG_DWORD)) { 00301 if (* (PULONG) ((PUCHAR) value + value->DataOffset)) { 00302 TempProfile.Flags = CM_HP_FLAGS_PRISTINE; 00303 // No other flags set; 00304 } 00305 } 00306 00307 // 00308 // If we see a profile with the ID of zero (AKA an illegal) 00309 // ID for a hardware profile to possess, then we know that this 00310 // must be a pristine profile. 00311 // 00312 if (0 == TempProfile.Id) { 00313 TempProfile.Flags = CM_HP_FLAGS_PRISTINE; 00314 // NO other flags set. 00315 00316 TempProfile.PreferenceOrder = -1; // move to the end of the list. 00317 } 00318 00319 00320 // 00321 // Insert this new profile into the appropriate spot in the 00322 // profile array. Entries are sorted by preference order. 00323 // 00324 for (j=0; j < (*ProfileList)->CurrentProfileCount; j++) { 00325 if ((*ProfileList)->Profile[j].PreferenceOrder >= 00326 TempProfile.PreferenceOrder) { 00327 00328 // 00329 // Insert at position j. 00330 // 00331 RtlMoveMemory(&(*ProfileList)->Profile[j+1], 00332 &(*ProfileList)->Profile[j], 00333 sizeof(CM_HARDWARE_PROFILE) * 00334 ((*ProfileList)->MaxProfileCount-j-1)); 00335 break; 00336 } 00337 } 00338 (*ProfileList)->Profile[j] = TempProfile; 00339 ++(*ProfileList)->CurrentProfileCount; 00340 00341 ZwClose (entry); 00342 } 00343 00344 // 00345 // Open a handle to the ACPI Alias information 00346 // 00347 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_ALIAS); 00348 InitializeObjectAttributes (&attributes, 00349 &name, 00350 OBJ_CASE_INSENSITIVE, 00351 IDConfigDB, 00352 NULL); 00353 status = ZwOpenKey (&acpiAlias, 00354 KEY_READ, 00355 &attributes); 00356 00357 if (!NT_SUCCESS (status)) { 00358 // 00359 // So we don't have an alias table. This is ok. 00360 // 00361 status = STATUS_SUCCESS; 00362 acpiAlias = NULL; 00363 goto Clean; 00364 } 00365 00366 // 00367 // Find the number of Acpi Alias Sub Keys 00368 // 00369 status = ZwQueryKey (acpiAlias, 00370 KeyFullInformation, 00371 &keyInfo, 00372 sizeof (keyInfo), 00373 &len); 00374 00375 if (!NT_SUCCESS (status)) { 00376 goto Clean; 00377 } 00378 00379 00380 ASSERT (0 < keyInfo.SubKeys); 00381 00382 * AliasList = ExAllocatePool ( 00383 PagedPool, 00384 sizeof (CM_HARDWARE_PROFILE_LIST) + 00385 (sizeof (CM_HARDWARE_PROFILE) * (keyInfo.SubKeys - 1))); 00386 00387 if (NULL == *AliasList) { 00388 status = STATUS_INSUFFICIENT_RESOURCES; 00389 goto Clean; 00390 } 00391 00392 (*AliasList)->MaxAliasCount = 00393 (*AliasList)->CurrentAliasCount = keyInfo.SubKeys; 00394 00395 // 00396 // Iterrate the alias entries 00397 // 00398 for (i = 0; i < keyInfo.SubKeys; i++) { 00399 00400 // 00401 // Get the first key in the list. 00402 // 00403 status = ZwEnumerateKey (acpiAlias, 00404 i, 00405 KeyBasicInformation, 00406 basicInfo, 00407 bufferLen - sizeof (UNICODE_NULL), // term 0 00408 &len); 00409 00410 if (!NT_SUCCESS (status)) { 00411 // 00412 // This should never happen. 00413 // 00414 break; 00415 } 00416 00417 basicInfo->Name [basicInfo->NameLength/sizeof(WCHAR)] = 0; 00418 name.Length = (USHORT) basicInfo->NameLength; 00419 name.MaximumLength = (USHORT) basicInfo->NameLength + sizeof (UNICODE_NULL); 00420 name.Buffer = basicInfo->Name; 00421 00422 InitializeObjectAttributes (&attributes, 00423 &name, 00424 OBJ_CASE_INSENSITIVE, 00425 acpiAlias, 00426 NULL); 00427 status = ZwOpenKey (&entry, 00428 KEY_READ, 00429 &attributes); 00430 if (!NT_SUCCESS (status)) { 00431 break; 00432 } 00433 00434 // 00435 // Extract The Profile number to which this alias refers. 00436 // 00437 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER); 00438 status = NtQueryValueKey(entry, 00439 &name, 00440 KeyValueFullInformation, 00441 valueBuffer, 00442 bufferLen, 00443 &len); 00444 00445 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 00446 status = STATUS_REGISTRY_CORRUPT; 00447 ZwClose (entry); 00448 goto Clean; 00449 } 00450 (*AliasList)->Alias[i].ProfileNumber = 00451 * (PULONG) ((PUCHAR) value + value->DataOffset); 00452 00453 // 00454 // Extract The Docking State. 00455 // 00456 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE); 00457 status = NtQueryValueKey(entry, 00458 &name, 00459 KeyValueFullInformation, 00460 valueBuffer, 00461 bufferLen, 00462 &len); 00463 00464 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 00465 status = STATUS_REGISTRY_CORRUPT; 00466 ZwClose (entry); 00467 goto Clean; 00468 } 00469 (*AliasList)->Alias[i].DockState = 00470 * (PULONG) ((PUCHAR) value + value->DataOffset); 00471 00472 00473 // 00474 // Find the SerialNumber 00475 // 00476 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_SERIAL_NUMBER); 00477 status = NtQueryValueKey(entry, 00478 &name, 00479 KeyValueFullInformation, 00480 valueBuffer, 00481 bufferLen, 00482 &len); 00483 00484 if (!NT_SUCCESS (status) || (value->Type != REG_BINARY)) { 00485 status = STATUS_REGISTRY_CORRUPT; 00486 ZwClose (entry); 00487 goto Clean; 00488 } 00489 00490 (*AliasList)->Alias[i].SerialLength = value->DataLength; 00491 (*AliasList)->Alias[i].SerialNumber = 00492 (value->DataLength) ? 00493 ExAllocatePool (PagedPool, value->DataLength) : 00494 0; 00495 00496 if (value->DataLength && (NULL == (*AliasList)->Alias[i].SerialNumber)) { 00497 00498 status = STATUS_INSUFFICIENT_RESOURCES; 00499 ZwClose (entry); 00500 goto Clean; 00501 } 00502 00503 if (value->DataLength) { 00504 RtlCopyMemory ((*AliasList)->Alias[i].SerialNumber, 00505 (PUCHAR) value + value->DataOffset, 00506 value->DataLength); 00507 } 00508 00509 ZwClose (entry); 00510 } 00511 00512 Clean: 00513 if (NULL != acpiAlias) { 00514 NtClose (acpiAlias); 00515 } 00516 if (NULL != profiles) { 00517 NtClose (profiles); 00518 } 00519 00520 if (!NT_SUCCESS (status)) { 00521 if (NULL != *ProfileList) { 00522 for (i = 0; i < (*ProfileList)->CurrentProfileCount; i++) { 00523 if ((*ProfileList)->Profile[i].FriendlyName) { 00524 ExFreePool ((*ProfileList)->Profile[i].FriendlyName); 00525 } 00526 } 00527 ExFreePool (*ProfileList); 00528 *ProfileList = 0; 00529 } 00530 if (NULL != *AliasList) { 00531 for (i = 0; i < (*AliasList)->CurrentAliasCount; i++) { 00532 if ((*AliasList)->Alias[i].SerialNumber) { 00533 ExFreePool ((*AliasList)->Alias[i].SerialNumber); 00534 } 00535 } 00536 ExFreePool (*AliasList); 00537 *AliasList = 0; 00538 } 00539 } 00540 return status; 00541 } 00542 00543 NTSTATUS 00544 CmpAddAcpiAliasEntry ( 00545 IN HANDLE IDConfigDB, 00546 IN PPROFILE_ACPI_DOCKING_STATE NewDockState, 00547 IN ULONG ProfileNumber, 00548 IN PWCHAR nameBuffer, 00549 IN PVOID valueBuffer, 00550 IN ULONG valueBufferLength, 00551 IN BOOLEAN PreventDuplication 00552 ) 00553 /*++ 00554 Routine Description: 00555 Set the Acpi Alais entry. 00556 00557 00558 Routine Description: 00559 Create an alias entry in the IDConfigDB database for the given 00560 hardware profile. 00561 00562 Create the "AcpiAlias" key if it does not exist. 00563 00564 Parameters: 00565 00566 IDConfigDB - Pointer to "..\CurrentControlSet\Control\IDConfigDB" 00567 00568 NewDockState - The new docking state for which this alias points. 00569 00570 ProfileNumber -The profile number to which this alias points. 00571 00572 nameBuffer - a temp scratch space for writing things. 00573 (assumed to be at least 128 WCHARS) 00574 00575 --*/ 00576 { 00577 OBJECT_ATTRIBUTES attributes; 00578 NTSTATUS status = STATUS_SUCCESS; 00579 ANSI_STRING ansiString; 00580 UNICODE_STRING name; 00581 HANDLE aliasKey = NULL; 00582 HANDLE aliasEntry = NULL; 00583 ULONG value; 00584 ULONG disposition; 00585 ULONG aliasNumber = 0; 00586 ULONG len; 00587 PKEY_VALUE_FULL_INFORMATION keyInfo; 00588 00589 PAGED_CODE (); 00590 00591 keyInfo = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 00592 00593 // 00594 // Find the Alias Key or Create it if it does not already exist. 00595 // 00596 RtlInitUnicodeString (&name,CM_HARDWARE_PROFILE_STR_ACPI_ALIAS); 00597 00598 InitializeObjectAttributes (&attributes, 00599 &name, 00600 OBJ_CASE_INSENSITIVE, 00601 IDConfigDB, 00602 NULL); 00603 00604 status = NtOpenKey (&aliasKey, 00605 KEY_READ | KEY_WRITE, 00606 &attributes); 00607 00608 if (STATUS_OBJECT_NAME_NOT_FOUND == status) { 00609 status = NtCreateKey (&aliasKey, 00610 KEY_READ | KEY_WRITE, 00611 &attributes, 00612 0, // no title 00613 NULL, // no class 00614 0, // no options 00615 &disposition); 00616 } 00617 00618 if (!NT_SUCCESS (status)) { 00619 aliasKey = NULL; 00620 goto Exit; 00621 } 00622 00623 // 00624 // Create an entry key 00625 // 00626 00627 while (aliasNumber < 200) { 00628 aliasNumber++; 00629 00630 swprintf (nameBuffer, L"%04d", aliasNumber); 00631 RtlInitUnicodeString (&name, nameBuffer); 00632 00633 InitializeObjectAttributes(&attributes, 00634 &name, 00635 OBJ_CASE_INSENSITIVE, 00636 aliasKey, 00637 NULL); 00638 00639 status = NtOpenKey (&aliasEntry, 00640 KEY_READ | KEY_WRITE, 00641 &attributes); 00642 00643 if (NT_SUCCESS (status)) { 00644 00645 if (PreventDuplication) { 00646 // 00647 // If we have a matching DockingState, SerialNumber, and 00648 // Profile Number, then we should not make this alias 00649 // 00650 00651 // 00652 // Extract The DockingState to which this alias refers. 00653 // 00654 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE); 00655 status = NtQueryValueKey(aliasEntry, 00656 &name, 00657 KeyValueFullInformation, 00658 valueBuffer, 00659 valueBufferLength, 00660 &len); 00661 00662 if (!NT_SUCCESS (status) || (keyInfo->Type != REG_DWORD)) { 00663 status = STATUS_REGISTRY_CORRUPT; 00664 goto Exit; 00665 } 00666 00667 if (NewDockState->DockingState != 00668 * (PULONG) ((PUCHAR) keyInfo + keyInfo->DataOffset)) { 00669 // 00670 // Not a dupe 00671 // 00672 00673 NtClose (aliasEntry); 00674 aliasEntry = NULL; 00675 continue; 00676 } 00677 00678 // 00679 // Extract the SerialNumber 00680 // 00681 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_SERIAL_NUMBER); 00682 status = NtQueryValueKey(aliasEntry, 00683 &name, 00684 KeyValueFullInformation, 00685 valueBuffer, 00686 valueBufferLength, 00687 &len); 00688 00689 if (!NT_SUCCESS (status) || (keyInfo->Type != REG_BINARY)) { 00690 status = STATUS_REGISTRY_CORRUPT; 00691 goto Exit; 00692 } 00693 00694 if (NewDockState->SerialLength != keyInfo->DataLength) { 00695 // 00696 // Not a dupe 00697 // 00698 00699 NtClose (aliasEntry); 00700 aliasEntry = NULL; 00701 continue; 00702 } 00703 00704 if (!RtlEqualMemory (NewDockState->SerialNumber, 00705 ((PUCHAR) keyInfo + keyInfo->DataOffset), 00706 NewDockState->SerialLength)) { 00707 // 00708 // Not a dupe 00709 // 00710 00711 NtClose (aliasEntry); 00712 aliasEntry = NULL; 00713 continue; 00714 } 00715 00716 status = STATUS_SUCCESS; 00717 goto Exit; 00718 00719 } 00720 00721 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { 00722 status = STATUS_SUCCESS; 00723 break; 00724 00725 } else { 00726 break; 00727 } 00728 00729 } 00730 if (!NT_SUCCESS (status)) { 00731 CMLOG(CML_BUGCHECK, CMS_INIT) { 00732 KdPrint(("CM: cmpCreateAcpiAliasEntry error finding new set %08lx\n", 00733 status)); 00734 } 00735 aliasEntry = 0; 00736 goto Exit; 00737 } 00738 00739 status = NtCreateKey (&aliasEntry, 00740 KEY_READ | KEY_WRITE, 00741 &attributes, 00742 0, 00743 NULL, 00744 0, 00745 &disposition); 00746 00747 if (!NT_SUCCESS (status)) { 00748 CMLOG(CML_BUGCHECK, CMS_INIT) { 00749 KdPrint(("CM: cmpCreateAcpiAliasEntry error creating new set %08lx\n", 00750 status)); 00751 } 00752 aliasEntry = 0; 00753 goto Exit; 00754 } 00755 00756 // 00757 // Write the Docking State; 00758 // 00759 value = NewDockState->DockingState; 00760 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE); 00761 status = NtSetValueKey (aliasEntry, 00762 &name, 00763 0, 00764 REG_DWORD, 00765 &value, 00766 sizeof (value)); 00767 00768 // 00769 // Write the Serial Number 00770 // 00771 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_SERIAL_NUMBER); 00772 status = NtSetValueKey (aliasEntry, 00773 &name, 00774 0, 00775 REG_BINARY, 00776 NewDockState->SerialNumber, 00777 NewDockState->SerialLength); 00778 00779 // 00780 // Write the Profile Number 00781 // 00782 value = ProfileNumber; 00783 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER); 00784 status = NtSetValueKey (aliasEntry, 00785 &name, 00786 0, 00787 REG_DWORD, 00788 &value, 00789 sizeof (value)); 00790 00791 Exit: 00792 00793 if (aliasKey) { 00794 NtClose (aliasKey); 00795 } 00796 00797 if (aliasEntry) { 00798 NtClose (aliasEntry); 00799 } 00800 00801 return status; 00802 } 00803 00804 NTSTATUS 00805 CmSetAcpiHwProfile ( 00806 IN PPROFILE_ACPI_DOCKING_STATE NewDockState, 00807 IN PCM_ACPI_SELECTION_ROUTINE Select, 00808 IN PVOID Context, 00809 OUT PHANDLE NewProfile, 00810 OUT PBOOLEAN ProfileChanged 00811 ) 00812 /*++ 00813 Routine Description: 00814 00815 The ACPI docking state of the machine has changed. 00816 00817 Based on the new change calculate the new HW Profile(s) consitent with the 00818 new ACPI docking state. 00819 00820 Pass the list of known profiles to the callers selection routine. 00821 00822 Set the new current profile. 00823 00824 Patch up any ACPI alias entries if a new profile for this ACPI state has 00825 been used. 00826 00827 Arguments: 00828 00829 NewDockStateArray - The list of possible Docking States that we might enter. 00830 00831 Select - Call back to select which profile to enter, given the list of 00832 possible profiles. 00833 00834 --*/ 00835 { 00836 NTSTATUS status = STATUS_SUCCESS; 00837 HANDLE IDConfigDB = NULL; 00838 HANDLE HardwareProfile = NULL; 00839 HANDLE currentInfo = NULL; 00840 HANDLE currentSymLink = NULL; 00841 HANDLE parent = NULL; 00842 WCHAR nameBuffer[128]; 00843 UNICODE_STRING name; 00844 UCHAR valueBuffer[256]; 00845 ULONG len; 00846 ULONG i; 00847 ULONG selectedElement; 00848 ULONG profileNum; 00849 ULONG currentDockingState; 00850 ULONG currentProfileNumber; 00851 ULONG disposition; 00852 ULONG flags; 00853 PWCHAR currentAcpiSN = NULL; 00854 PCM_HARDWARE_PROFILE_ACPI_ALIAS_LIST AliasList = NULL; 00855 PCM_HARDWARE_PROFILE_LIST ProfileList = NULL; 00856 PKEY_VALUE_FULL_INFORMATION value; 00857 OBJECT_ATTRIBUTES attributes; 00858 00859 PAGED_CODE (); 00860 00861 *ProfileChanged = FALSE; 00862 00863 value = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 00864 00865 // 00866 // Open The Hardware Profile Database 00867 // 00868 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DATABASE); 00869 InitializeObjectAttributes (&attributes, 00870 &name, 00871 OBJ_CASE_INSENSITIVE, 00872 NULL, 00873 NULL); 00874 00875 status = ZwOpenKey (&IDConfigDB, 00876 KEY_READ, 00877 &attributes); 00878 00879 if (!NT_SUCCESS (status)) { 00880 IDConfigDB = NULL; 00881 goto Clean; 00882 } 00883 00884 // 00885 // Obtain the total list of profiles 00886 // 00887 status = CmpGetAcpiProfileInformation (IDConfigDB, 00888 &ProfileList, 00889 &AliasList, 00890 nameBuffer, 00891 valueBuffer, 00892 sizeof (valueBuffer)); 00893 00894 if (!NT_SUCCESS (status)) { 00895 goto Clean; 00896 } 00897 00898 // 00899 // Determine the current Dock information. 00900 // 00901 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CCS_CURRENT); 00902 InitializeObjectAttributes (&attributes, 00903 &name, 00904 OBJ_CASE_INSENSITIVE, 00905 NULL, 00906 NULL); 00907 00908 status = ZwOpenKey (&HardwareProfile, 00909 KEY_READ, 00910 &attributes); 00911 if (!NT_SUCCESS (status)) { 00912 HardwareProfile = NULL; 00913 goto Clean; 00914 } 00915 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CURRENT_DOCK_INFO); 00916 InitializeObjectAttributes (&attributes, 00917 &name, 00918 OBJ_CASE_INSENSITIVE, 00919 IDConfigDB, 00920 NULL); 00921 00922 status = ZwOpenKey (&currentInfo, 00923 KEY_READ, 00924 &attributes); 00925 if (!NT_SUCCESS (status)) { 00926 currentInfo = NULL; 00927 goto Clean; 00928 } 00929 00930 // 00931 // The current Docking State 00932 // 00933 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE); 00934 status = NtQueryValueKey (currentInfo, 00935 &name, 00936 KeyValueFullInformation, 00937 valueBuffer, 00938 sizeof (valueBuffer), 00939 &len); 00940 00941 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 00942 status = STATUS_REGISTRY_CORRUPT; 00943 goto Clean; 00944 } 00945 currentDockingState = * (PULONG) ((PUCHAR) value + value->DataOffset); 00946 00947 // 00948 // The current ACPI Serial Number 00949 // 00950 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_SERIAL_NUMBER); 00951 status = NtQueryValueKey(currentInfo, 00952 &name, 00953 KeyValueFullInformation, 00954 valueBuffer, 00955 sizeof (valueBuffer), 00956 &len); 00957 00958 if (NT_SUCCESS (status) && (value->Type == REG_BINARY)) { 00959 00960 currentAcpiSN = ExAllocatePool (PagedPool, value->DataLength); 00961 00962 if (NULL == currentAcpiSN) { 00963 status = STATUS_INSUFFICIENT_RESOURCES; 00964 goto Clean; 00965 } 00966 RtlCopyMemory (currentAcpiSN, 00967 (PUCHAR) value + value->DataOffset, 00968 value->DataLength); 00969 } else { 00970 currentAcpiSN = 0; 00971 } 00972 00973 // 00974 // The current Profile Number 00975 // 00976 RtlInitUnicodeString(&name, L"CurrentConfig"); 00977 status = NtQueryValueKey(IDConfigDB, 00978 &name, 00979 KeyValueFullInformation, 00980 valueBuffer, 00981 sizeof (valueBuffer), 00982 &len); 00983 00984 if (!NT_SUCCESS(status) || (value->Type != REG_DWORD)) { 00985 status = STATUS_REGISTRY_CORRUPT; 00986 goto Clean; 00987 } 00988 currentProfileNumber = *(PULONG)((PUCHAR)value + value->DataOffset); 00989 00990 // 00991 // Filter the current list of hardware profiles based on the current 00992 // docking state, the new acpi state, and the acpi alias tables 00993 // 00994 status = CmpFilterAcpiDockingState (NewDockState, 00995 currentDockingState, 00996 currentAcpiSN, 00997 currentProfileNumber, 00998 ProfileList, 00999 AliasList); 01000 01001 if (!NT_SUCCESS (status)) { 01002 goto Clean; 01003 } 01004 01005 // 01006 // Allow the caller a chance to select from the filtered list. 01007 // 01008 status = Select (ProfileList, &selectedElement, Context); 01009 01010 // 01011 // If the user selected -1 then he is not interested in selecting any of 01012 // the profiles. 01013 // 01014 if (-1 == selectedElement) { 01015 ASSERT (STATUS_MORE_PROCESSING_REQUIRED == status); 01016 goto Clean; 01017 } 01018 01019 if (!NT_SUCCESS (status)) { 01020 goto Clean; 01021 } 01022 01023 // 01024 // Fine! We have finally made the new selection. 01025 // Set it. 01026 // 01027 01028 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CCS_HWPROFILE); 01029 InitializeObjectAttributes (&attributes, 01030 &name, 01031 OBJ_CASE_INSENSITIVE, 01032 NULL, 01033 NULL); 01034 status = ZwOpenKey (&parent, KEY_READ, &attributes); 01035 if (!NT_SUCCESS (status)) { 01036 parent = NULL; 01037 goto Clean; 01038 } 01039 01040 // 01041 // How did we get here? 01042 // 01043 flags = ProfileList->Profile[selectedElement].Flags; 01044 profileNum = ProfileList->Profile[selectedElement].Id; 01045 01046 // 01047 // Check for duplicate 01048 // 01049 if (flags & CM_HP_FLAGS_DUPLICATE) { 01050 // 01051 // If there is a duplicate then we need to adjust the pnp 01052 // bios alias table. 01053 // 01054 // This happens if we booted PnP bios detected docked, and then 01055 // we received a set state for ACPI as docked, then we have the 01056 // potential for duplicates. See Comment in CmpFilterAcpiDockingState 01057 // for details. 01058 // 01059 // We need to find any pnp bios alias entries that match the current 01060 // state and point them to the duplicate entry. 01061 // 01062 01063 ASSERT (flags & CM_HP_FLAGS_TRUE_MATCH); 01064 ASSERT (!(flags & CM_HP_FLAGS_PRISTINE)); 01065 01066 status = CmpMoveBiosAliasTable (IDConfigDB, 01067 currentInfo, 01068 currentProfileNumber, 01069 profileNum, 01070 nameBuffer, 01071 valueBuffer, 01072 sizeof (valueBuffer)); 01073 01074 if (!NT_SUCCESS (status)) { 01075 goto Clean; 01076 } 01077 } 01078 01079 if ((flags & CM_HP_FLAGS_PRISTINE) || (profileNum != currentProfileNumber)){ 01080 // 01081 // The profile Number Changed or will change. 01082 // 01083 *ProfileChanged = TRUE; 01084 01085 ASSERT (currentInfo); 01086 ZwClose (currentInfo); 01087 currentInfo = NULL; 01088 01089 if (flags & CM_HP_FLAGS_PRISTINE) { 01090 // 01091 // If the selected profile is pristine then we need to clone. 01092 // 01093 ASSERT (!(flags & CM_HP_FLAGS_TRUE_MATCH)); 01094 status = CmpCloneHwProfile (IDConfigDB, 01095 parent, 01096 HardwareProfile, 01097 profileNum, 01098 NewDockState->DockingState, 01099 &HardwareProfile, 01100 &profileNum); 01101 if (!NT_SUCCESS (status)) { 01102 HardwareProfile = 0; 01103 goto Clean; 01104 } 01105 } else { 01106 ASSERT (HardwareProfile); 01107 ZwClose (HardwareProfile); 01108 01109 // 01110 // Open the new profile 01111 // 01112 swprintf (nameBuffer, L"%04d\0", profileNum); 01113 RtlInitUnicodeString (&name, nameBuffer); 01114 InitializeObjectAttributes (&attributes, 01115 &name, 01116 OBJ_CASE_INSENSITIVE, 01117 parent, 01118 NULL); 01119 status = ZwOpenKey (&HardwareProfile, KEY_READ, &attributes); 01120 if (!NT_SUCCESS (status)) { 01121 HardwareProfile = NULL; 01122 goto Clean; 01123 } 01124 } 01125 01126 ASSERT (currentProfileNumber != profileNum); 01127 01128 // 01129 // Open the current info for the profile. 01130 // 01131 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CURRENT_DOCK_INFO); 01132 InitializeObjectAttributes (&attributes, 01133 &name, 01134 OBJ_CASE_INSENSITIVE, 01135 IDConfigDB, 01136 NULL); 01137 01138 status = NtCreateKey (&currentInfo, 01139 KEY_READ | KEY_WRITE, 01140 &attributes, 01141 0, 01142 NULL, 01143 REG_OPTION_VOLATILE, 01144 &disposition); 01145 01146 if (!NT_SUCCESS (status)) { 01147 currentInfo = NULL; 01148 goto Clean; 01149 } 01150 01151 // 01152 // Set CurrentConfig in the Database 01153 // 01154 RtlInitUnicodeString(&name, L"CurrentConfig"); 01155 status = NtSetValueKey(IDConfigDB, 01156 &name, 01157 0, 01158 REG_DWORD, 01159 &profileNum, 01160 sizeof (profileNum)); 01161 01162 if (!NT_SUCCESS(status)) { 01163 status = STATUS_REGISTRY_CORRUPT; 01164 goto Clean; 01165 } 01166 } 01167 01168 // 01169 // Write the new Docking State to the current Info key 01170 // 01171 i = NewDockState->DockingState; 01172 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKING_STATE); 01173 status = ZwSetValueKey (currentInfo, 01174 &name, 01175 0, 01176 REG_DWORD, 01177 &i, 01178 sizeof (ULONG)); 01179 01180 // 01181 // Write the new ACPI information to the current Info key 01182 // 01183 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ACPI_SERIAL_NUMBER); 01184 status = ZwSetValueKey (currentInfo, 01185 &name, 01186 0, 01187 REG_BINARY, 01188 NewDockState->SerialNumber, 01189 NewDockState->SerialLength); 01190 01191 if (!(flags & CM_HP_FLAGS_TRUE_MATCH)) { 01192 // 01193 // Add the alias entry for this profile. 01194 // 01195 status = CmpAddAcpiAliasEntry (IDConfigDB, 01196 NewDockState, 01197 profileNum, 01198 nameBuffer, 01199 valueBuffer, 01200 sizeof (valueBuffer), 01201 FALSE); // Don't Prevent Duplication 01202 } 01203 01204 if (profileNum != currentProfileNumber) { 01205 // 01206 // Move the symbolic link. 01207 // 01208 RtlInitUnicodeString(&name, CM_HARDWARE_PROFILE_STR_CCS_CURRENT); 01209 InitializeObjectAttributes(&attributes, 01210 &name, 01211 OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, 01212 NULL, 01213 NULL); 01214 01215 status = NtCreateKey(&currentSymLink, 01216 KEY_CREATE_LINK, 01217 &attributes, 01218 0, 01219 NULL, 01220 REG_OPTION_OPEN_LINK, 01221 &disposition); 01222 01223 ASSERT (STATUS_SUCCESS == status); 01224 ASSERT (REG_OPENED_EXISTING_KEY == disposition); 01225 01226 swprintf (nameBuffer, 01227 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\%04d", 01228 profileNum); 01229 RtlInitUnicodeString (&name, nameBuffer); 01230 status = NtSetValueKey (currentSymLink, 01231 &CmSymbolicLinkValueName, 01232 0, 01233 REG_LINK, 01234 name.Buffer, 01235 name.Length); 01236 01237 ASSERT (STATUS_SUCCESS == status); 01238 } 01239 01240 01241 Clean: 01242 if (NT_SUCCESS (status)) { 01243 // NB more process required is not a success code. 01244 *NewProfile = HardwareProfile; 01245 } else if (NULL != HardwareProfile) { 01246 ZwClose (HardwareProfile); 01247 } 01248 01249 if (NULL != IDConfigDB) { 01250 ZwClose (IDConfigDB); 01251 } 01252 if (NULL != currentInfo) { 01253 ZwClose (currentInfo); 01254 } 01255 if (NULL != parent) { 01256 ZwClose (parent); 01257 } 01258 if (NULL != currentAcpiSN) { 01259 ExFreePool (currentAcpiSN); 01260 } 01261 if (NULL != ProfileList) { 01262 for (i = 0; i < ProfileList->CurrentProfileCount; i++) { 01263 if (ProfileList->Profile[i].FriendlyName) { 01264 ExFreePool (ProfileList->Profile[i].FriendlyName); 01265 } 01266 } 01267 ExFreePool (ProfileList); 01268 } 01269 if (NULL != AliasList) { 01270 for (i = 0; i < AliasList->CurrentAliasCount; i++) { 01271 if (AliasList->Alias[i].SerialNumber) { 01272 ExFreePool (AliasList->Alias[i].SerialNumber); 01273 } 01274 } 01275 ExFreePool (AliasList); 01276 } 01277 01278 return status; 01279 } 01280 01281 NTSTATUS 01282 CmpFilterAcpiDockingState ( 01283 IN PPROFILE_ACPI_DOCKING_STATE NewDockingState, 01284 IN ULONG CurrentDockState, 01285 IN PWCHAR CurrentAcpiSN, 01286 IN ULONG CurrentProfileNumber, 01287 IN OUT PCM_HARDWARE_PROFILE_LIST ProfileList, 01288 IN OUT PCM_HARDWARE_PROFILE_ACPI_ALIAS_LIST AliasList 01289 ) 01290 /*++ 01291 Routine Description: 01292 Given the new state of things and the current state of things, 01293 prune the given list of profiles. 01294 01295 --*/ 01296 { 01297 NTSTATUS status = STATUS_SUCCESS; 01298 ULONG i = 0; 01299 ULONG j; 01300 ULONG len; 01301 ULONG mask = HW_PROFILE_DOCKSTATE_UNDOCKED | HW_PROFILE_DOCKSTATE_DOCKED; 01302 ULONG flags; 01303 PCM_HARDWARE_PROFILE_ACPI_ALIAS alias; 01304 BOOLEAN trueMatch = FALSE; 01305 BOOLEAN dupDetect = FALSE; 01306 BOOLEAN currentListed = FALSE; 01307 BOOLEAN keepCurrent = FALSE; 01308 01309 PAGED_CODE (); 01310 01311 // 01312 // Check for duplicate: 01313 // 01314 // If the user boots undocked, and then hot docks. We will generate 01315 // a profile alias for the pnp reported undocked state [A], and one for the 01316 // ACPI reported docked state [B}. If the use subsequently reboots docked, 01317 // then we will create a third pnp reported docked state [C] profile alias. 01318 // {C] is really a duplicate of [B}, but we wont know this until such time 01319 // as the ACPI state for {B] is reported. 01320 // 01321 // The same can happen for undocked scenerios. 01322 // 01323 // Detection: If the Current Dock State is the same as 01324 // NewDockingState.DockingState then there is a potential for a duplicate. 01325 // In order to also have a duplicate we must have an acpi already pointing 01326 // to a profile different than the current one. 01327 // This must also be the first ACPI change since we booted, therefore 01328 // CurrentAcpiSn Should be Zero. 01329 // In other words there must be at least one true match and none of the 01330 // true matches can point to the current profile. 01331 // 01332 01333 if (AliasList) { 01334 while (i < AliasList->CurrentAliasCount) { 01335 alias = &AliasList->Alias[i]; 01336 01337 if (((alias->DockState & mask) != 0) && 01338 ((alias->DockState & mask) != 01339 (NewDockingState->DockingState & mask))) { 01340 01341 // 01342 // This alias claims to be docked or undocked, but does not 01343 // match the current state. Therefore skip it. 01344 // 01345 ; 01346 01347 } else if (alias->SerialLength != NewDockingState->SerialLength) { 01348 // 01349 // This alias has an incompatible serial number 01350 // 01351 ; 01352 01353 } else if (alias->SerialLength == 01354 RtlCompareMemory (NewDockingState->SerialNumber, 01355 alias->SerialNumber, 01356 alias->SerialLength)) { 01357 // 01358 // NB RtlCompareMemory can work with zero length memory 01359 // addresses. This is a requirement here. 01360 // 01361 01362 01363 01364 // 01365 // This alias matches so mark the profile. 01366 // 01367 for (j = 0; j < ProfileList->CurrentProfileCount; j++) { 01368 if (ProfileList->Profile[j].Id == alias->ProfileNumber) { 01369 01370 // 01371 // Alias entries should never point to a pristine profile 01372 // 01373 ASSERT (!(ProfileList->Profile[j].Flags & 01374 CM_HP_FLAGS_PRISTINE)); 01375 01376 ProfileList->Profile[j].Flags |= CM_HP_FLAGS_TRUE_MATCH; 01377 trueMatch = TRUE; 01378 } 01379 if ((CurrentDockState == NewDockingState->DockingState) && 01380 (NULL == CurrentAcpiSN)) { 01381 // 01382 // The dock state did not change during this acpi 01383 // event; therefore, we might just have a duplicate 01384 // on our hands. 01385 // 01386 dupDetect = TRUE; 01387 } 01388 if (alias->ProfileNumber == CurrentProfileNumber) { 01389 // 01390 // There exists an entry in the acpi alias table that 01391 // if chosen would result in no change of Hardware 01392 // Profile. Therefore, we should chose this one, and 01393 // ignore the duplicate. 01394 // 01395 currentListed = TRUE; 01396 } 01397 } 01398 } 01399 i++; 01400 } 01401 } 01402 01403 if ((!dupDetect) && 01404 (NULL == CurrentAcpiSN) && 01405 (!trueMatch) && 01406 (CurrentDockState == NewDockingState->DockingState)) { 01407 01408 // 01409 // (1) The docking state did not change, 01410 // (2) the current profile has not yet, on this boot, been marked with 01411 // an ACPI serial number. 01412 // (3) There was no Alias match. 01413 // 01414 // Therefore we should keep the current profile regardless of it being 01415 // aliasable. 01416 // 01417 01418 keepCurrent = TRUE; 01419 trueMatch = TRUE; // prevent pristine from being listed. 01420 } 01421 01422 i = 0; 01423 while (i < ProfileList->CurrentProfileCount) { 01424 01425 flags = ProfileList->Profile[i].Flags; 01426 01427 if (dupDetect) { 01428 if (flags & CM_HP_FLAGS_TRUE_MATCH) { 01429 if (currentListed) { 01430 if (ProfileList->Profile[i].Id == CurrentProfileNumber) { 01431 // 01432 // Let this one live. This results in no change of 01433 // profile number. 01434 // 01435 i++; 01436 continue; 01437 } 01438 // 01439 // Bounce any true matches that do not result in no change 01440 // of profile. 01441 // 01442 ; 01443 01444 } else { 01445 // 01446 // We did not find the current one listed so we definately 01447 // have a duplicate. 01448 // 01449 // Mark it as such. and list it live. 01450 // 01451 ProfileList->Profile[i].Flags |= CM_HP_FLAGS_DUPLICATE; 01452 i++; 01453 continue; 01454 } 01455 } 01456 // 01457 // Bounce all non True matches in a duplicate detected situation. 01458 // 01459 ; 01460 01461 } else if ((flags & CM_HP_FLAGS_PRISTINE) && !trueMatch) { 01462 // 01463 // Leave this one in the list 01464 // 01465 i++; 01466 continue; 01467 01468 } else if (flags & CM_HP_FLAGS_ALIASABLE) { 01469 // 01470 // Leave this one in the list 01471 // 01472 ASSERT (! (flags & CM_HP_FLAGS_PRISTINE)); 01473 i++; 01474 continue; 01475 01476 } else if (flags & CM_HP_FLAGS_TRUE_MATCH) { 01477 // 01478 // Leave this one in the list 01479 // 01480 i++; 01481 continue; 01482 01483 } else if (keepCurrent && 01484 (ProfileList->Profile[i].Id == CurrentProfileNumber)) { 01485 // 01486 // Leave this one in the list 01487 // 01488 i++; 01489 continue; 01490 } 01491 01492 // 01493 // discard this profile by (1) shifting remaining profiles in 01494 // array to fill in the space of this discarded profile 01495 // and (2) decrementing profile count 01496 // 01497 len = ProfileList->CurrentProfileCount - i - 1; 01498 if (0 < len) { 01499 RtlMoveMemory(&ProfileList->Profile[i], 01500 &ProfileList->Profile[i+1], 01501 sizeof(CM_HARDWARE_PROFILE) * len); 01502 } 01503 01504 --ProfileList->CurrentProfileCount; 01505 } 01506 01507 return status; 01508 } 01509 01510 01511 01512 NTSTATUS 01513 CmpMoveBiosAliasTable ( 01514 IN HANDLE IDConfigDB, 01515 IN HANDLE CurrentInfo, 01516 IN ULONG CurrentProfileNumber, 01517 IN ULONG NewProfileNumber, 01518 IN PWCHAR nameBuffer, 01519 IN PCHAR valueBuffer, 01520 IN ULONG bufferLen 01521 ) 01522 /*++ 01523 Routine Description: 01524 Search the Alias table for bios entries which match the current 01525 docking state, and point from current profile number to new profile number. 01526 01527 01528 Assumption: If the profile is cloned (therefore created by 01529 CmpCloneHwProfile, and we have just moved the bios table to point 01530 away from this entry, then we *should* be able to safely delete 01531 the old hardware profile key. 01532 (in both IDConfigDB\HardwareProfiles and CCS\HardwareProfiles 01533 01534 01535 --*/ 01536 { 01537 NTSTATUS status = STATUS_SUCCESS; 01538 HANDLE alias = NULL; 01539 HANDLE entry = NULL; 01540 HANDLE hwprofile = NULL; 01541 UNICODE_STRING name; 01542 ULONG currentDockId; 01543 ULONG currentSerialNumber; 01544 ULONG len; 01545 ULONG i; 01546 OBJECT_ATTRIBUTES attributes; 01547 KEY_FULL_INFORMATION keyInfo; 01548 PKEY_BASIC_INFORMATION basicInfo; 01549 PKEY_VALUE_FULL_INFORMATION value; 01550 01551 PAGED_CODE (); 01552 01553 value = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 01554 basicInfo = (PKEY_BASIC_INFORMATION) valueBuffer; 01555 01556 // 01557 // Extract the current Serial Number and DockID 01558 // 01559 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_SERIAL_NUMBER); 01560 status = NtQueryValueKey(CurrentInfo, 01561 &name, 01562 KeyValueFullInformation, 01563 valueBuffer, 01564 bufferLen, 01565 &len); 01566 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01567 status = STATUS_REGISTRY_CORRUPT; 01568 goto Clean; 01569 } 01570 currentSerialNumber = * (PULONG) ((PUCHAR) value + value->DataOffset); 01571 01572 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKID); 01573 status = NtQueryValueKey(CurrentInfo, 01574 &name, 01575 KeyValueFullInformation, 01576 valueBuffer, 01577 bufferLen, 01578 &len); 01579 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01580 status = STATUS_REGISTRY_CORRUPT; 01581 goto Clean; 01582 } 01583 currentDockId = * (PULONG) ((PUCHAR) value + value->DataOffset); 01584 01585 // 01586 // Open a handle to the Alias information 01587 // 01588 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ALIAS); 01589 InitializeObjectAttributes (&attributes, 01590 &name, 01591 OBJ_CASE_INSENSITIVE, 01592 IDConfigDB, 01593 NULL); 01594 status = ZwOpenKey (&alias, 01595 KEY_READ, 01596 &attributes); 01597 01598 if (!NT_SUCCESS (status)) { 01599 // 01600 // So we don't have an alias table. This is ok, albeit a bit strange 01601 // 01602 status = STATUS_SUCCESS; 01603 alias = NULL; 01604 goto Clean; 01605 } 01606 01607 01608 status = ZwQueryKey (alias, 01609 KeyFullInformation, 01610 &keyInfo, 01611 sizeof (keyInfo), 01612 &len); 01613 01614 if (!NT_SUCCESS (status)) { 01615 goto Clean; 01616 } 01617 ASSERT (0 < keyInfo.SubKeys); 01618 01619 // 01620 // Iterrate the alias entries 01621 // 01622 for (i = 0; i < keyInfo.SubKeys; i++) { 01623 01624 // 01625 // Get the first key in the list. 01626 // 01627 status = ZwEnumerateKey (alias, 01628 i, 01629 KeyBasicInformation, 01630 basicInfo, 01631 bufferLen - sizeof (UNICODE_NULL), // term 0 01632 &len); 01633 01634 if (!NT_SUCCESS (status)) { 01635 // 01636 // This should never happen. 01637 // 01638 break; 01639 } 01640 01641 basicInfo->Name [basicInfo->NameLength/sizeof(WCHAR)] = 0; 01642 name.Length = (USHORT) basicInfo->NameLength; 01643 name.MaximumLength = (USHORT) basicInfo->NameLength + sizeof (UNICODE_NULL); 01644 name.Buffer = basicInfo->Name; 01645 01646 InitializeObjectAttributes (&attributes, 01647 &name, 01648 OBJ_CASE_INSENSITIVE, 01649 alias, 01650 NULL); 01651 status = ZwOpenKey (&entry, 01652 KEY_READ | KEY_WRITE, 01653 &attributes); 01654 if (!NT_SUCCESS (status)) { 01655 break; 01656 } 01657 01658 // 01659 // Extract The Profile number to which this alias refers. 01660 // 01661 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER); 01662 status = NtQueryValueKey(entry, 01663 &name, 01664 KeyValueFullInformation, 01665 valueBuffer, 01666 bufferLen, 01667 &len); 01668 01669 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01670 status = STATUS_REGISTRY_CORRUPT; 01671 goto Clean; 01672 } 01673 01674 if (CurrentProfileNumber != *(PULONG)((PUCHAR)value + value->DataOffset)) { 01675 01676 // 01677 // Not a match 01678 // 01679 ZwClose (entry); 01680 entry = NULL; 01681 continue; 01682 } 01683 01684 // 01685 // Compare the Dock ID 01686 // 01687 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_DOCKID); 01688 status = NtQueryValueKey(entry, 01689 &name, 01690 KeyValueFullInformation, 01691 valueBuffer, 01692 bufferLen, 01693 &len); 01694 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01695 status = STATUS_REGISTRY_CORRUPT; 01696 goto Clean; 01697 } 01698 if (currentDockId != * (PULONG) ((PUCHAR) value + value->DataOffset)) { 01699 // 01700 // Not a match 01701 // 01702 ZwClose (entry); 01703 entry = NULL; 01704 continue; 01705 } 01706 01707 // 01708 // Compare the SerialNumber 01709 // 01710 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_SERIAL_NUMBER); 01711 status = NtQueryValueKey(entry, 01712 &name, 01713 KeyValueFullInformation, 01714 valueBuffer, 01715 bufferLen, 01716 &len); 01717 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01718 status = STATUS_REGISTRY_CORRUPT; 01719 goto Clean; 01720 } 01721 if (currentSerialNumber != *(PULONG)((PUCHAR)value + value->DataOffset)) { 01722 // 01723 // Not a match 01724 // 01725 ZwClose (entry); 01726 entry = NULL; 01727 continue; 01728 } 01729 01730 // 01731 // This must be a match. 01732 // move the profile number 01733 // 01734 01735 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PROFILE_NUMBER); 01736 status = NtSetValueKey (entry, 01737 &name, 01738 0, 01739 REG_DWORD, 01740 &NewProfileNumber, 01741 sizeof (NewProfileNumber)); 01742 01743 ASSERT (STATUS_SUCCESS == status); 01744 01745 ZwClose (entry); 01746 entry = NULL; 01747 01748 // 01749 // We most likely have left a dangling profile here. 01750 // Try to attempt to clean it up. 01751 // 01752 // If this profile is cloned then we created it and can therefore 01753 // get rid of it. 01754 // 01755 01756 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_HARDWARE_PROFILES); 01757 InitializeObjectAttributes (&attributes, 01758 &name, 01759 OBJ_CASE_INSENSITIVE, 01760 IDConfigDB, 01761 NULL); 01762 status = ZwOpenKey (&hwprofile, KEY_READ | KEY_WRITE, &attributes); 01763 if (!NT_SUCCESS (status)) { 01764 hwprofile = NULL; 01765 status = STATUS_REGISTRY_CORRUPT; 01766 goto Clean; 01767 } 01768 01769 swprintf (nameBuffer, L"%04d\0", CurrentProfileNumber); 01770 RtlInitUnicodeString (&name, nameBuffer); 01771 InitializeObjectAttributes (&attributes, 01772 &name, 01773 OBJ_CASE_INSENSITIVE, 01774 hwprofile, 01775 NULL); 01776 status = ZwOpenKey (&entry, KEY_ALL_ACCESS, &attributes); 01777 if (!NT_SUCCESS (status)) { 01778 entry = NULL; 01779 status = STATUS_REGISTRY_CORRUPT; 01780 goto Clean; 01781 } 01782 01783 // 01784 // Test for the Cloned Bit. 01785 // 01786 01787 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CLONED); 01788 status = NtQueryValueKey(entry, 01789 &name, 01790 KeyValueFullInformation, 01791 valueBuffer, 01792 bufferLen, 01793 &len); 01794 01795 if (!NT_SUCCESS (status) || (value->Type != REG_DWORD)) { 01796 status = STATUS_REGISTRY_CORRUPT; 01797 goto Clean; 01798 } 01799 01800 if (*(PULONG)((PUCHAR)value + value->DataOffset)) { 01801 // 01802 // We cloned this one. 01803 // 01804 status = ZwDeleteKey (entry); 01805 ASSERT (NT_SUCCESS (status)); 01806 01807 ZwClose (entry); 01808 ZwClose (hwprofile); 01809 entry = hwprofile = NULL; 01810 01811 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CCS_HWPROFILE); 01812 InitializeObjectAttributes (&attributes, 01813 &name, 01814 OBJ_CASE_INSENSITIVE, 01815 NULL, 01816 NULL); 01817 status = ZwOpenKey (&hwprofile, KEY_READ | KEY_WRITE, &attributes); 01818 if (!NT_SUCCESS (status)) { 01819 hwprofile = NULL; 01820 status = STATUS_REGISTRY_CORRUPT; 01821 goto Clean; 01822 } 01823 01824 swprintf (nameBuffer, L"%04d\0", CurrentProfileNumber); 01825 01826 status = CmDeleteKeyRecursive (hwprofile, 01827 nameBuffer, 01828 valueBuffer, 01829 bufferLen, 01830 TRUE); 01831 01832 ASSERT (NT_SUCCESS (status)); 01833 ZwClose (hwprofile); 01834 hwprofile = NULL; 01835 01836 } else { 01837 // 01838 // We didn't clone this one. 01839 // don't do anything else. 01840 // 01841 ZwClose (entry); 01842 ZwClose (hwprofile); 01843 entry = hwprofile = NULL; 01844 } 01845 01846 CM_HARDWARE_PROFILE_STR_CCS_HWPROFILE; 01847 01848 01849 01850 } 01851 01852 Clean: 01853 01854 if (alias) { 01855 ZwClose (alias); 01856 } 01857 if (entry) { 01858 ZwClose (entry); 01859 } 01860 if (hwprofile) { 01861 ZwClose (hwprofile); 01862 } 01863 01864 return status; 01865 } 01866 01867 01868 NTSTATUS 01869 CmpCloneHwProfile ( 01870 IN HANDLE IDConfigDB, 01871 IN HANDLE Parent, 01872 IN HANDLE OldProfile, 01873 IN ULONG OldProfileNumber, 01874 IN USHORT DockingState, 01875 OUT PHANDLE NewProfile, 01876 OUT PULONG NewProfileNumber 01877 ) 01878 /*++ 01879 Routine Description 01880 01881 The given hardware profile key needs cloning. 01882 Clone the key and then return the new profile. 01883 01884 Return: 01885 01886 STATUS_SUCCESS - if the profile has been cloned, in which case the new 01887 profile key has been opened for read / write privs. The old profile 01888 will be closed. 01889 01890 <unsuccessful> - for a given error. NewProfile is invalid and the Old 01891 Profile has also been closed. 01892 01893 01894 (Copied lovingly from CmpCloneControlSet) 01895 01896 01897 --*/ 01898 { 01899 NTSTATUS status = STATUS_SUCCESS; 01900 UNICODE_STRING newProfileName; 01901 UNICODE_STRING name; 01902 UNICODE_STRING friendlyName; 01903 UNICODE_STRING guidStr; 01904 PCM_KEY_BODY oldProfileKey; 01905 PCM_KEY_BODY newProfileKey; 01906 OBJECT_ATTRIBUTES attributes; 01907 PSECURITY_DESCRIPTOR security; 01908 ULONG securityLength; 01909 WCHAR nameBuffer [64]; 01910 HANDLE IDConfigDBEntry = NULL; 01911 ULONG disposition; 01912 ULONG value; 01913 UUID uuid; 01914 PKEY_BASIC_INFORMATION keyBasicInfo; 01915 PKEY_FULL_INFORMATION keyFullInfo; 01916 PKEY_VALUE_FULL_INFORMATION keyValueInfo; 01917 ULONG length, profileSubKeys, i; 01918 UCHAR valueBuffer[256]; 01919 HANDLE hardwareProfiles=NULL; 01920 HANDLE profileEntry=NULL; 01921 01922 PAGED_CODE (); 01923 01924 keyFullInfo = (PKEY_FULL_INFORMATION) valueBuffer; 01925 keyBasicInfo = (PKEY_BASIC_INFORMATION) valueBuffer; 01926 keyValueInfo = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 01927 01928 *NewProfile = 0; 01929 *NewProfileNumber = OldProfileNumber; 01930 01931 // 01932 // Find the new profile number. 01933 // 01934 01935 while (*NewProfileNumber < 200) { 01936 (*NewProfileNumber)++; 01937 01938 swprintf (nameBuffer, L"%04d", *NewProfileNumber); 01939 RtlInitUnicodeString (&newProfileName, nameBuffer); 01940 01941 InitializeObjectAttributes(&attributes, 01942 &newProfileName, 01943 OBJ_CASE_INSENSITIVE, 01944 Parent, 01945 NULL); 01946 01947 status = NtOpenKey (NewProfile, 01948 KEY_READ | KEY_WRITE, 01949 &attributes); 01950 01951 if (NT_SUCCESS (status)) { 01952 NtClose (*NewProfile); 01953 01954 } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { 01955 status = STATUS_SUCCESS; 01956 break; 01957 01958 } else { 01959 break; 01960 } 01961 01962 } 01963 if (!NT_SUCCESS (status)) { 01964 CMLOG(CML_BUGCHECK, CMS_INIT) { 01965 KdPrint(("CM: CmpCloneHwProfile error finding new profile key %08lx\n", status)); 01966 } 01967 goto Exit; 01968 } 01969 01970 // 01971 // Get the security descriptor from the old key to create the new clone one. 01972 // 01973 01974 status = NtQuerySecurityObject (OldProfile, 01975 DACL_SECURITY_INFORMATION, 01976 NULL, 01977 0, 01978 &securityLength); 01979 01980 if (STATUS_BUFFER_TOO_SMALL == status) { 01981 01982 security = ExAllocatePool (PagedPool, securityLength); 01983 01984 if (security != NULL) { 01985 status = NtQuerySecurityObject(OldProfile, 01986 DACL_SECURITY_INFORMATION, 01987 security, 01988 securityLength, 01989 &securityLength); 01990 if (!NT_SUCCESS (status)) { 01991 CMLOG(CML_BUGCHECK, CMS_INIT) { 01992 KdPrint(("CM: CmpCloneHwProfile" 01993 " - NtQuerySecurityObject failed %08lx\n", status)); 01994 } 01995 ExFreePool(security); 01996 security=NULL; 01997 } 01998 } 01999 } else { 02000 CMLOG(CML_BUGCHECK, CMS_INIT) { 02001 KdPrint(("CM: CmpCloneHwProfile" 02002 " - NtQuerySecurityObject returned %08lx\n", status)); 02003 } 02004 security=NULL; 02005 } 02006 02007 // 02008 // Create the new key 02009 // 02010 InitializeObjectAttributes (&attributes, 02011 &newProfileName, 02012 OBJ_CASE_INSENSITIVE, 02013 Parent, 02014 security); 02015 02016 status = NtCreateKey (NewProfile, 02017 KEY_READ | KEY_WRITE, 02018 &attributes, 02019 0, 02020 NULL, 02021 0, 02022 &disposition); 02023 02024 if (NULL != security) { 02025 ExFreePool (security); 02026 } 02027 if (!NT_SUCCESS (status)) { 02028 CMLOG(CML_BUGCHECK, CMS_INIT) { 02029 KdPrint(("CM: CmpCloneHwProfile couldn't create Clone %08lx\n",status)); 02030 } 02031 goto Exit; 02032 } 02033 02034 // 02035 // Check to make sure the key was created. If it already exists, 02036 // something is wrong. 02037 // 02038 if (disposition != REG_CREATED_NEW_KEY) { 02039 CMLOG(CML_BUGCHECK, CMS_INIT) { 02040 // KdPrint(("CM: CmpCloneHwProfile: Clone tree already exists!\n")); 02041 } 02042 02043 // 02044 // WARNNOTE: 02045 // If somebody somehow managed to create a key in our way, 02046 // they'll thwart duplication of the prestine. Tough luck. 02047 // Claim it worked and go on. 02048 // 02049 status = STATUS_SUCCESS; 02050 goto Exit; 02051 } 02052 02053 // 02054 // Create the IDConfigDB Entry 02055 // 02056 swprintf (nameBuffer, L"Hardware Profiles\\%04d", *NewProfileNumber); 02057 RtlInitUnicodeString (&name, nameBuffer); 02058 02059 InitializeObjectAttributes (&attributes, 02060 &name, 02061 OBJ_CASE_INSENSITIVE, 02062 IDConfigDB, 02063 NULL); 02064 02065 status = NtCreateKey (&IDConfigDBEntry, 02066 KEY_READ | KEY_WRITE, 02067 &attributes, 02068 0, 02069 NULL, 02070 0, 02071 &disposition); 02072 02073 if (!NT_SUCCESS (status)) { 02074 CMLOG(CML_BUGCHECK, CMS_INIT) { 02075 KdPrint(("CM: CmpCloneHwProfile couldn't create Clone %08lx\n",status)); 02076 } 02077 IDConfigDBEntry = NULL; 02078 goto Exit; 02079 } 02080 02081 // 02082 // Determine the next PreferenceOrder for the new profile. (The 02083 // PrefenceOrder for the new profile will be incrementally next from the 02084 // greatest PreferenceOrder value of all the current profiles; assumes 02085 // current set of PreferenceOrder values is incremental) 02086 // 02087 02088 // 02089 // Open the Hardware Profiles key 02090 // 02091 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_HARDWARE_PROFILES); 02092 02093 InitializeObjectAttributes (&attributes, 02094 &name, 02095 OBJ_CASE_INSENSITIVE, 02096 IDConfigDB, 02097 NULL); 02098 status = ZwOpenKey (&hardwareProfiles, 02099 KEY_READ, 02100 &attributes); 02101 02102 if (!NT_SUCCESS (status)) { 02103 hardwareProfiles = NULL; 02104 goto Exit; 02105 } 02106 02107 // 02108 // Find the number of profile Sub Keys 02109 // 02110 status = ZwQueryKey (hardwareProfiles, 02111 KeyFullInformation, 02112 valueBuffer, 02113 sizeof (valueBuffer), 02114 &length); 02115 02116 if (!NT_SUCCESS (status)) { 02117 goto Exit; 02118 } 02119 02120 // 02121 // At very least, the Pristine and the new profile key we just created, 02122 // should be there. 02123 // 02124 profileSubKeys = keyFullInfo->SubKeys; 02125 ASSERT (1 < profileSubKeys); 02126 02127 // 02128 // Initialize the highest PreferenceOrder value found to -1. 02129 // 02130 value = -1; 02131 02132 // 02133 // Iterrate the profiles 02134 // 02135 for (i = 0; i < profileSubKeys; i++) { 02136 02137 // 02138 // Enumerate all profile subkeys, noting their PreferenceOrder values. 02139 // 02140 status = ZwEnumerateKey (hardwareProfiles, 02141 i, 02142 KeyBasicInformation, 02143 valueBuffer, 02144 sizeof(valueBuffer) - sizeof (UNICODE_NULL), //term 0 02145 &length); 02146 if(!NT_SUCCESS(status)) { 02147 break; 02148 } 02149 02150 // 02151 // Zero-terminate the subkey name just in case. 02152 // 02153 keyBasicInfo->Name[keyBasicInfo->NameLength/sizeof(WCHAR)] = 0; 02154 02155 // 02156 // If this is the Pristine, or the NewProfile key, ignore it. 02157 // 02158 if ((!_wtoi(keyBasicInfo->Name)) || 02159 ((ULONG)(_wtoi(keyBasicInfo->Name)) == *NewProfileNumber)) { 02160 continue; 02161 } 02162 02163 // 02164 // Open this profile key 02165 // 02166 name.Length = (USHORT) keyBasicInfo->NameLength; 02167 name.MaximumLength = (USHORT) keyBasicInfo->NameLength + sizeof (UNICODE_NULL); 02168 name.Buffer = keyBasicInfo->Name; 02169 02170 InitializeObjectAttributes (&attributes, 02171 &name, 02172 OBJ_CASE_INSENSITIVE, 02173 hardwareProfiles, 02174 NULL); 02175 status = ZwOpenKey (&profileEntry, 02176 KEY_READ, 02177 &attributes); 02178 if (!NT_SUCCESS (status)) { 02179 profileEntry = NULL; 02180 continue; 02181 } 02182 02183 // 02184 // Extract The PreferenceOrder value for this Profile. 02185 // 02186 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PREFERENCE_ORDER); 02187 status = NtQueryValueKey(profileEntry, 02188 &name, 02189 KeyValueFullInformation, 02190 valueBuffer, 02191 sizeof(valueBuffer), 02192 &length); 02193 02194 if (!NT_SUCCESS (status) || (keyValueInfo->Type != REG_DWORD)) { 02195 // 02196 // No PreferenceOrder; continue on as best we can 02197 // 02198 ZwClose(profileEntry); 02199 profileEntry=NULL; 02200 continue; 02201 } 02202 02203 // 02204 // If this is a the highest PreferenceOrder so far, reassign value to 02205 // this PreferenceOrder, OR assign it this valid PreferenceOrder if 02206 // value is still unassigned. 02207 // 02208 if (((*(PULONG) ((PUCHAR)keyValueInfo + keyValueInfo->DataOffset)) > value) || 02209 (value == -1)) { 02210 value = (* (PULONG) ((PUCHAR)keyValueInfo + keyValueInfo->DataOffset)); 02211 } 02212 02213 ZwClose(profileEntry); 02214 profileEntry=NULL; 02215 } 02216 02217 // 02218 // Increment value one above the greatest PreferenceOrder found. 02219 // (If no other profiles were found, (value+=1) == 0, the most preferred 02220 // profile) 02221 // 02222 value += 1; 02223 02224 // 02225 // Give the new profile a preference order. 02226 // 02227 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_PREFERENCE_ORDER); 02228 status = NtSetValueKey (IDConfigDBEntry, 02229 &name, 02230 0, 02231 REG_DWORD, 02232 &value, 02233 sizeof (value)); 02234 02235 // 02236 // Give the new profile a friendly name, based on the DockingState 02237 // 02238 status = CmpCreateHwProfileFriendlyName(IDConfigDB, 02239 DockingState, 02240 *NewProfileNumber, 02241 &friendlyName); 02242 02243 if (NT_SUCCESS(status)) { 02244 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_FRIENDLY_NAME); 02245 status = NtSetValueKey (IDConfigDBEntry, 02246 &name, 02247 0, 02248 REG_SZ, 02249 friendlyName.Buffer, 02250 friendlyName.Length + sizeof(UNICODE_NULL)); 02251 RtlFreeUnicodeString(&friendlyName); 02252 } 02253 02254 // 02255 // Set the aliasable flag on the new "cloned profile" to be false 02256 // 02257 value = FALSE; 02258 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_ALIASABLE); 02259 status = NtSetValueKey (IDConfigDBEntry, 02260 &name, 02261 0, 02262 REG_DWORD, 02263 &value, 02264 sizeof (value)); 02265 02266 // 02267 // Set the cloned profile on the new "cloned profile" to be true; 02268 // 02269 value = TRUE; 02270 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_CLONED); 02271 status = NtSetValueKey (IDConfigDBEntry, 02272 &name, 02273 0, 02274 REG_DWORD, 02275 &value, 02276 sizeof (value)); 02277 02278 // 02279 // Set the HwProfileGuid for the brand new profile 02280 // 02281 02282 status = ExUuidCreate (&uuid); 02283 if (NT_SUCCESS (status)) { 02284 02285 status = RtlStringFromGUID (&uuid, &guidStr); 02286 if (NT_SUCCESS (status)) { 02287 RtlInitUnicodeString (&name, CM_HARDWARE_PROFILE_STR_HW_PROFILE_GUID); 02288 02289 status = NtSetValueKey (IDConfigDBEntry, 02290 &name, 02291 0, 02292 REG_SZ, 02293 guidStr.Buffer, 02294 guidStr.MaximumLength); 02295 02296 RtlFreeUnicodeString(&guidStr); 02297 } else { 02298 // 02299 // What's a fella to do? 02300 // let's just go on. 02301 // 02302 status = STATUS_SUCCESS; 02303 } 02304 02305 } else { 02306 // 02307 // let's just go on. 02308 // 02309 status = STATUS_SUCCESS; 02310 } 02311 02312 02313 // 02314 // Clone the key 02315 // 02316 // (Copied lovingly from CmpCloneControlSet) 02317 // 02318 // 02319 status = ObReferenceObjectByHandle (OldProfile, 02320 KEY_READ, 02321 CmpKeyObjectType, 02322 KernelMode, 02323 (PVOID *)(&oldProfileKey), 02324 NULL); 02325 02326 if (!NT_SUCCESS(status)) { 02327 CMLOG(CML_BUGCHECK, CMS_INIT) { 02328 KdPrint(("CM: CmpCloneHWProfile: couldn't reference CurrentHandle %08lx\n", 02329 status)); 02330 } 02331 goto Exit; 02332 } 02333 02334 ObReferenceObjectByHandle (*NewProfile, 02335 KEY_WRITE, 02336 CmpKeyObjectType, 02337 KernelMode, 02338 (PVOID *)(&newProfileKey), 02339 NULL); 02340 02341 if (!NT_SUCCESS(status)) { 02342 CMLOG(CML_BUGCHECK, CMS_INIT) { 02343 KdPrint(("CM: CmpCloneHWProfile: couldn't reference CurrentHandle %08lx\n", 02344 status)); 02345 } 02346 goto Exit; 02347 } 02348 02349 CmpLockRegistryExclusive(); 02350 02351 // 02352 // Note: This copy tree command does not copy the values in the 02353 // root keys. We are relying on this, since the values stored there 02354 // are things like "pristine" which we do not wish to have moved to the 02355 // new tree. 02356 // 02357 if (CmpCopyTree(oldProfileKey->KeyControlBlock->KeyHive, 02358 oldProfileKey->KeyControlBlock->KeyCell, 02359 newProfileKey->KeyControlBlock->KeyHive, 02360 newProfileKey->KeyControlBlock->KeyCell)) { 02361 // 02362 // Set the max subkey name property for the new target key. 02363 // 02364 newProfileKey->KeyControlBlock->KeyNode->MaxNameLen = 02365 oldProfileKey->KeyControlBlock->KeyNode->MaxNameLen; 02366 status = STATUS_SUCCESS; 02367 } else { 02368 CMLOG(CML_BUGCHECK, CMS_INIT) { 02369 KdPrint(("CM: CmpCloneHwProfile: tree copy failed.\n")); 02370 } 02371 status = STATUS_REGISTRY_CORRUPT; 02372 } 02373 CmpUnlockRegistry(); 02374 02375 02376 Exit: 02377 NtClose (OldProfile); 02378 if (IDConfigDBEntry) { 02379 NtClose (IDConfigDBEntry); 02380 } 02381 if (hardwareProfiles) { 02382 NtClose (hardwareProfiles); 02383 } 02384 if (!NT_SUCCESS (status)) { 02385 if (*NewProfile) { 02386 NtClose (*NewProfile); 02387 } 02388 } 02389 02390 return status; 02391 } 02392 02393 NTSTATUS 02394 CmDeleteKeyRecursive( 02395 HANDLE hKeyRoot, 02396 PWSTR Key, 02397 PVOID TemporaryBuffer, 02398 ULONG LengthTemporaryBuffer, 02399 BOOLEAN ThisKeyToo 02400 ) 02401 /*++ 02402 02403 Routine Description: 02404 02405 Routine to recursively delete all subkeys under the given 02406 key, including the key given. 02407 02408 Arguments: 02409 02410 hKeyRoot: Handle to root relative to which the key to be deleted is 02411 specified. 02412 02413 Key: Root relative path of the key which is to be recursively deleted. 02414 02415 ThisKeyToo: Whether after deletion of all subkeys, this key itself is to 02416 be deleted. 02417 02418 Return Value: 02419 02420 Status is returned. 02421 02422 --*/ 02423 { 02424 ULONG ResultLength; 02425 PKEY_BASIC_INFORMATION KeyInfo; 02426 NTSTATUS Status; 02427 UNICODE_STRING UnicodeString; 02428 OBJECT_ATTRIBUTES Obja; 02429 PWSTR SubkeyName; 02430 HANDLE hKey; 02431 02432 // 02433 // Initialize 02434 // 02435 02436 KeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer; 02437 02438 // 02439 // Open the key 02440 // 02441 02442 RtlInitUnicodeString (&UnicodeString,Key); 02443 02444 InitializeObjectAttributes(&Obja, 02445 &UnicodeString, 02446 OBJ_CASE_INSENSITIVE, 02447 hKeyRoot, 02448 NULL); 02449 02450 Status = ZwOpenKey(&hKey,KEY_ALL_ACCESS,&Obja); 02451 if( !NT_SUCCESS(Status) ) { 02452 return(Status); 02453 } 02454 02455 // 02456 // Enumerate all subkeys of the current key. if any exist they should 02457 // be deleted first. since deleting the subkey affects the subkey 02458 // index, we always enumerate on subkeyindex 0 02459 // 02460 while(1) { 02461 Status = ZwEnumerateKey( 02462 hKey, 02463 0, 02464 KeyBasicInformation, 02465 TemporaryBuffer, 02466 LengthTemporaryBuffer, 02467 &ResultLength 02468 ); 02469 if(!NT_SUCCESS(Status)) { 02470 break; 02471 } 02472 02473 // 02474 // Zero-terminate the subkey name just in case. 02475 // 02476 KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0; 02477 02478 // 02479 // Make a duplicate of the subkey name because the name is 02480 // in TemporaryBuffer, which might get clobbered by recursive 02481 // calls to this routine. 02482 // 02483 SubkeyName = ExAllocatePool (PagedPool, 02484 ((wcslen (KeyInfo->Name) + 1) * 02485 sizeof (WCHAR))); 02486 if (!SubkeyName) { 02487 Status = STATUS_INSUFFICIENT_RESOURCES; 02488 break; 02489 } 02490 wcscpy(SubkeyName, KeyInfo->Name); 02491 Status = CmDeleteKeyRecursive( hKey, 02492 SubkeyName, 02493 TemporaryBuffer, 02494 LengthTemporaryBuffer, 02495 TRUE); 02496 ExFreePool(SubkeyName); 02497 if(!NT_SUCCESS(Status)) { 02498 break; 02499 } 02500 } 02501 02502 // 02503 // Check the status, if the status is anything other than 02504 // STATUS_NO_MORE_ENTRIES we failed in deleting some subkey, 02505 // so we cannot delete this key too 02506 // 02507 02508 if( Status == STATUS_NO_MORE_ENTRIES) { 02509 Status = STATUS_SUCCESS; 02510 } 02511 02512 if (!NT_SUCCESS (Status)) { 02513 ZwClose(hKey); 02514 return (Status); 02515 } 02516 02517 // 02518 // else delete the current key if asked to do so 02519 // 02520 if( ThisKeyToo ) { 02521 Status = ZwDeleteKey (hKey); 02522 } 02523 02524 ZwClose(hKey); 02525 return(Status); 02526 } 02527 02528 NTSTATUS 02529 CmpCreateHwProfileFriendlyName ( 02530 IN HANDLE IDConfigDB, 02531 IN ULONG DockingState, 02532 IN ULONG NewProfileNumber, 02533 OUT PUNICODE_STRING FriendlyName 02534 ) 02535 /*++ 02536 02537 Routine Description: 02538 02539 Create a new FriendlyName for a new Hardware Profile, given the DockState. 02540 If a new profile name based on the DockState cannot be created, an attempt 02541 is made to create a default FriendlyName based on NewProfileNumber. If 02542 successful, a unicode string with the new profile friendlyName is created. 02543 It is the responsibility of the caller to free this using 02544 RtlFreeUnicodeString. If unsuccesful, no string is returned. 02545 02546 Arguments: 02547 02548 IDConfigDB: Handle to the IDConfigDB registry key. 02549 02550 DockingState: The Docking State of the profile for which the new 02551 FriendlyName is being created. This should be one of: 02552 HW_PROFILE_DOCKSTATE_DOCKED, 02553 HW_PROFILE_DOCKSTATE_UNDOCKED, or 02554 HW_PROFILE_DOCKSTATE_UNKNOWN 02555 02556 NewProfileNumber: The number of the new profile being created. If unable to 02557 create a DockState specific FriendlyName, this value will 02558 be used to create a (not-so) FriendlyName. 02559 02560 FriendlyName: Supplies a unicode string to receive the FriendlyName for this 02561 new profile. The caller is expected to free this with 02562 RtlFreeUnicodeString. 02563 02564 Return: 02565 02566 NTSTATUS code. Currently returns STATUS_SUCCESS, or STATUS_UNSUCCESSFUL. 02567 02568 Notes: 02569 02570 The new FriendlyName is generated from the DockState and appropriate 02571 counter, and may not necessarily be unique among the existing Hardware 02572 Profiles. 02573 02574 The naming scheme used here (including the localized strings in the kernel 02575 message table) should be kept in sync with that provided to the user through 02576 the Hardware Profile control panel applet. 02577 02578 --*/ 02579 { 02580 NTSTATUS status = STATUS_SUCCESS; 02581 ANSI_STRING ansiString; 02582 UNICODE_STRING unicodeString; 02583 UNICODE_STRING labelName, keyName; 02584 PMESSAGE_RESOURCE_ENTRY messageEntry; 02585 PLDR_DATA_TABLE_ENTRY dataTableEntry; 02586 ULONG messageId; 02587 UCHAR valueBuffer[256]; 02588 WCHAR friendlyNameBuffer[MAX_FRIENDLY_NAME_LENGTH/sizeof(WCHAR)]; 02589 PKEY_VALUE_FULL_INFORMATION keyValueInfo; 02590 ULONG length, index; 02591 HANDLE hardwareProfiles=NULL; 02592 OBJECT_ATTRIBUTES attributes; 02593 02594 PAGED_CODE (); 02595 02596 // 02597 // Make sure we were given a place to put the FriendlyName 02598 // 02599 if (!FriendlyName) { 02600 return STATUS_INVALID_PARAMETER; 02601 } 02602 02603 // 02604 // If we don't have a handle to IDConfigDB, try to assign a default 02605 // FriendlyName on the way out. 02606 // 02607 if (!IDConfigDB) { 02608 status = STATUS_INVALID_PARAMETER; 02609 goto Exit; 02610 } 02611 02612 // 02613 // Determine the appropriate message to use, based on the DockState. 02614 // 02615 if ((DockingState & HW_PROFILE_DOCKSTATE_UNKNOWN) == HW_PROFILE_DOCKSTATE_UNKNOWN){ 02616 messageId = HARDWARE_PROFILE_UNKNOWN_STRING; 02617 RtlInitUnicodeString(&labelName, CM_HARDWARE_PROFILE_STR_UNKNOWN); 02618 } else if (DockingState & HW_PROFILE_DOCKSTATE_DOCKED) { 02619 messageId = HARDWARE_PROFILE_DOCKED_STRING; 02620 RtlInitUnicodeString(&labelName, CM_HARDWARE_PROFILE_STR_DOCKED); 02621 } else if (DockingState & HW_PROFILE_DOCKSTATE_UNDOCKED) { 02622 messageId = HARDWARE_PROFILE_UNDOCKED_STRING; 02623 RtlInitUnicodeString(&labelName, CM_HARDWARE_PROFILE_STR_UNDOCKED); 02624 } else { 02625 messageId = HARDWARE_PROFILE_UNKNOWN_STRING; 02626 RtlInitUnicodeString(&labelName, CM_HARDWARE_PROFILE_STR_UNKNOWN); 02627 } 02628 02629 // 02630 // Find the message entry in the kernel's own message table. KeLoaderBlock 02631 // is available when we're creating hardware profiles during system 02632 // initialization only; for profiles created thereafter, use the the first 02633 // entry of the PsLoadedModuleList to get the image base of the kernel. 02634 // 02635 if (KeLoaderBlock) { 02636 dataTableEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink, 02637 LDR_DATA_TABLE_ENTRY, 02638 InLoadOrderLinks); 02639 } else if (PsLoadedModuleList.Flink) { 02640 dataTableEntry = CONTAINING_RECORD(PsLoadedModuleList.Flink, 02641 LDR_DATA_TABLE_ENTRY, 02642 InLoadOrderLinks); 02643 } else { 02644 status = STATUS_UNSUCCESSFUL; 02645 goto Exit; 02646 } 02647 02648 status = RtlFindMessage(dataTableEntry->DllBase, 02649 (ULONG_PTR)11, // RT_MESSAGETABLE 02650 MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT), // System default language 02651 messageId, 02652 &messageEntry); 02653 02654 if (!NT_SUCCESS(status)) { 02655 goto Exit; 02656 } 02657 02658 if(!(messageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) { 02659 // 02660 // If the message is not unicode, convert to unicode. 02661 // Let the conversion routine allocate the buffer. 02662 // 02663 RtlInitAnsiString(&ansiString,messageEntry->Text); 02664 status = RtlAnsiStringToUnicodeString(&unicodeString,&ansiString,TRUE); 02665 } else { 02666 // 02667 // Message is already unicode. Make a copy. 02668 // 02669 status = RtlCreateUnicodeString(&unicodeString,(PWSTR)messageEntry->Text); 02670 } 02671 02672 if(!NT_SUCCESS(status)) { 02673 goto Exit; 02674 } 02675 02676 // 02677 // Strip the trailing CRLF. 02678 // 02679 if (unicodeString.Length > 2 * sizeof(WCHAR)) { 02680 unicodeString.Length -= 2 * sizeof(WCHAR); 02681 unicodeString.Buffer[unicodeString.Length / sizeof(WCHAR)] = UNICODE_NULL; 02682 } 02683 02684 // 02685 // Check that the size of the label, with any numeric tag that may 02686 // potentially be added (up to 4 digits, preceded by a space) is not too 02687 // big. 02688 // 02689 if ((unicodeString.Length + 5*sizeof(WCHAR) + sizeof(UNICODE_NULL)) > 02690 MAX_FRIENDLY_NAME_LENGTH) { 02691 status = STATUS_UNSUCCESSFUL; 02692 goto Clean; 02693 } 02694 02695 // 02696 // Open the Hardware Profiles key. 02697 // 02698 RtlInitUnicodeString(&keyName, CM_HARDWARE_PROFILE_STR_HARDWARE_PROFILES); 02699 InitializeObjectAttributes(&attributes, 02700 &keyName, 02701 OBJ_CASE_INSENSITIVE, 02702 IDConfigDB, 02703 NULL); 02704 status = ZwOpenKey(&hardwareProfiles, 02705 KEY_READ, 02706 &attributes); 02707 if (!NT_SUCCESS(status)) { 02708 hardwareProfiles = NULL; 02709 goto Clean; 02710 } 02711 02712 // 02713 // Retrieve the counter of FriendlyNames we have previously assigned, based 02714 // on this DockState. 02715 // 02716 keyValueInfo = (PKEY_VALUE_FULL_INFORMATION) valueBuffer; 02717 status = ZwQueryValueKey(hardwareProfiles, 02718 &labelName, 02719 KeyValueFullInformation, 02720 valueBuffer, 02721 sizeof(valueBuffer), 02722 &length); 02723 02724 if (NT_SUCCESS(status) && (keyValueInfo->Type == REG_DWORD)) { 02725 // 02726 // Increment the counter. 02727 // 02728 index = (* (PULONG) ((PUCHAR)keyValueInfo + keyValueInfo->DataOffset)); 02729 index++; 02730 } else { 02731 // 02732 // Missing or invalid counter value; start the counter at "1". 02733 // 02734 index = 1; 02735 } 02736 02737 // 02738 // Update the counter in the registry. 02739 // 02740 status = ZwSetValueKey(hardwareProfiles, 02741 &labelName, 02742 0, 02743 REG_DWORD, 02744 &index, 02745 sizeof(index)); 02746 if (!NT_SUCCESS(status)) { 02747 goto Clean; 02748 } 02749 02750 // 02751 // Copy the FriendlyName, adding the index if necessary. 02752 // 02753 if ((messageId == HARDWARE_PROFILE_UNKNOWN_STRING) || (index > 1)) { 02754 swprintf(friendlyNameBuffer, L"%s %u", 02755 unicodeString.Buffer, index); 02756 } else { 02757 wcscpy(friendlyNameBuffer, unicodeString.Buffer); 02758 } 02759 02760 Clean: 02761 02762 RtlFreeUnicodeString(&unicodeString); 02763 02764 if (hardwareProfiles!=NULL) { 02765 ZwClose(hardwareProfiles); 02766 } 02767 02768 Exit: 02769 02770 if (!NT_SUCCESS(status)) { 02771 // 02772 // If we failed to assign a counter-based FriendlyName for whatever 02773 // reason, give the new profile a new (not so) friendly name as a last 02774 // resort. 02775 // 02776 swprintf (friendlyNameBuffer, L"%04d", NewProfileNumber); 02777 status = STATUS_SUCCESS; 02778 } 02779 02780 // 02781 // Create the unicode string to return to the caller. 02782 // 02783 if (!RtlCreateUnicodeString(FriendlyName, (PWSTR)friendlyNameBuffer)) { 02784 status = STATUS_UNSUCCESSFUL; 02785 } 02786 02787 return status; 02788 02789 } // CmpCreateHwProfileFriendlyName

Generated on Sat May 15 19:40:18 2004 for test by doxygen 1.3.7