1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002-2004, 2007 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "videoprt.h"
23 #include <ndk/obfuncs.h>
24 #include <stdio.h>
25
26 #define NDEBUG
27 #include <debug.h>
28
29 NTSTATUS
30 NTAPI
IntCopyRegistryKey(_In_ HANDLE SourceKeyHandle,_In_ HANDLE DestKeyHandle)31 IntCopyRegistryKey(
32 _In_ HANDLE SourceKeyHandle,
33 _In_ HANDLE DestKeyHandle)
34 {
35 PVOID InfoBuffer;
36 PKEY_BASIC_INFORMATION KeyInformation;
37 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
38 OBJECT_ATTRIBUTES ObjectAttributes;
39 ULONG Index, InformationLength, RequiredLength;
40 UNICODE_STRING NameString;
41 NTSTATUS Status;
42 HANDLE SourceSubKeyHandle, DestSubKeyHandle;
43
44 /* Start with no buffer, set initial size */
45 InfoBuffer = NULL;
46 InformationLength = 256;
47
48 /* Start looping with key index 0 */
49 Index = 0;
50 while (TRUE)
51 {
52 /* Check if we have no buffer */
53 if (InfoBuffer == NULL)
54 {
55 /* Allocate a new buffer */
56 InfoBuffer = ExAllocatePoolWithTag(PagedPool,
57 InformationLength,
58 TAG_VIDEO_PORT_BUFFER);
59 if (InfoBuffer == NULL)
60 {
61 ERR_(VIDEOPRT, "Could not allocate buffer for key info\n");
62 return STATUS_INSUFFICIENT_RESOURCES;
63 }
64 }
65
66 /* Enumerate the next sub-key */
67 KeyInformation = InfoBuffer;
68 Status = ZwEnumerateKey(SourceKeyHandle,
69 Index,
70 KeyBasicInformation,
71 KeyInformation,
72 InformationLength,
73 &RequiredLength);
74 if ((Status == STATUS_BUFFER_OVERFLOW) ||
75 (Status == STATUS_BUFFER_TOO_SMALL))
76 {
77 /* Free the buffer and remember the required size */
78 ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
79 InfoBuffer = NULL;
80 InformationLength = RequiredLength;
81
82 /* Try again */
83 continue;
84 }
85 else if (Status == STATUS_NO_MORE_ENTRIES)
86 {
87 /* We are done with the sub-keys */
88 break;
89 }
90 else if (!NT_SUCCESS(Status))
91 {
92 ERR_(VIDEOPRT, "ZwEnumerateKey failed, status 0x%lx\n", Status);
93 goto Cleanup;
94 }
95
96 /* Initialize a unicode string from the key name */
97 NameString.Buffer = KeyInformation->Name;
98 NameString.Length = (USHORT)KeyInformation->NameLength;
99 NameString.MaximumLength = NameString.Length;
100
101 /* Initialize object attributes and open the source sub-key */
102 InitializeObjectAttributes(&ObjectAttributes,
103 &NameString,
104 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
105 SourceKeyHandle,
106 NULL);
107 Status = ZwOpenKey(&SourceSubKeyHandle, KEY_READ, &ObjectAttributes);
108 if (!NT_SUCCESS(Status))
109 {
110 ERR_(VIDEOPRT, "failed to open the source key.\n");
111 goto Cleanup;
112 }
113
114 /* Initialize object attributes and create the dest sub-key */
115 InitializeObjectAttributes(&ObjectAttributes,
116 &NameString,
117 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
118 DestKeyHandle,
119 NULL);
120 Status = ZwCreateKey(&DestSubKeyHandle,
121 KEY_WRITE,
122 &ObjectAttributes,
123 0,
124 NULL,
125 REG_OPTION_NON_VOLATILE,
126 NULL);
127 if (!NT_SUCCESS(Status))
128 {
129 ERR_(VIDEOPRT, "failed to create the destination key.\n");
130 ObCloseHandle(SourceSubKeyHandle, KernelMode);
131 goto Cleanup;
132 }
133
134 /* Recursively copy the sub-key */
135 Status = IntCopyRegistryKey(SourceSubKeyHandle, DestSubKeyHandle);
136 if (!NT_SUCCESS(Status))
137 {
138 /* Just warn, but continue with the remaining sub-keys */
139 WARN_(VIDEOPRT, "failed to copy subkey '%wZ'.\n", &NameString);
140 }
141
142 /* Close the sub-key handles */
143 ObCloseHandle(SourceSubKeyHandle, KernelMode);
144 ObCloseHandle(DestSubKeyHandle, KernelMode);
145
146 /* Next sub-key */
147 Index++;
148 }
149
150 /* Start looping with value index 0 */
151 Index = 0;
152 while (TRUE)
153 {
154 /* Check if we have no buffer */
155 if (InfoBuffer == NULL)
156 {
157 /* Allocate a new buffer */
158 InfoBuffer = ExAllocatePoolWithTag(PagedPool,
159 InformationLength,
160 TAG_VIDEO_PORT_BUFFER);
161 if (InfoBuffer == NULL)
162 {
163 ERR_(VIDEOPRT, "Could not allocate buffer for key values\n");
164 return Status;
165 }
166 }
167
168 /* Enumerate the next value */
169 KeyValueInformation = InfoBuffer;
170 Status = ZwEnumerateValueKey(SourceKeyHandle,
171 Index,
172 KeyValueFullInformation,
173 KeyValueInformation,
174 InformationLength,
175 &RequiredLength);
176 if ((Status == STATUS_BUFFER_OVERFLOW) ||
177 (Status == STATUS_BUFFER_TOO_SMALL))
178 {
179 /* Free the buffer and remember the required size */
180 ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
181 InfoBuffer = NULL;
182 InformationLength = RequiredLength;
183
184 /* Try again */
185 continue;
186 }
187 else if (Status == STATUS_NO_MORE_ENTRIES)
188 {
189 /* We are done with the values */
190 Status = STATUS_SUCCESS;
191 break;
192 }
193 else if (!NT_SUCCESS(Status))
194 {
195 ERR_(VIDEOPRT, "ZwEnumerateValueKey failed, status 0x%lx\n", Status);
196 goto Cleanup;
197 }
198
199 /* Initialize a unicode string from the value name */
200 NameString.Buffer = KeyValueInformation->Name;
201 NameString.Length = (USHORT)KeyValueInformation->NameLength;
202 NameString.MaximumLength = NameString.Length;
203
204 /* Create the key value in the destination key */
205 Status = ZwSetValueKey(DestKeyHandle,
206 &NameString,
207 KeyValueInformation->TitleIndex,
208 KeyValueInformation->Type,
209 (PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
210 KeyValueInformation->DataLength);
211 if (!NT_SUCCESS(Status))
212 {
213 /* Just warn, but continue with the remaining sub-keys */
214 WARN_(VIDEOPRT, "failed to set value '%wZ'.\n", &NameString);
215 }
216
217 /* Next subkey */
218 Index++;
219 }
220
221 Cleanup:
222 /* Free the buffer and return the failure code */
223 if (InfoBuffer != NULL)
224 ExFreePoolWithTag(InfoBuffer, TAG_VIDEO_PORT_BUFFER);
225 return Status;
226 }
227
228 NTSTATUS
229 NTAPI
IntCopyRegistryValue(HANDLE SourceKeyHandle,HANDLE DestKeyHandle,PWSTR ValueName)230 IntCopyRegistryValue(
231 HANDLE SourceKeyHandle,
232 HANDLE DestKeyHandle,
233 PWSTR ValueName)
234 {
235 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
236 UNICODE_STRING ValueNameString;
237 ULONG Length;
238 NTSTATUS Status;
239
240 RtlInitUnicodeString(&ValueNameString, ValueName);
241
242 /* Query the value length */
243 Status = ZwQueryValueKey(SourceKeyHandle,
244 &ValueNameString,
245 KeyValuePartialInformation,
246 NULL,
247 0,
248 &Length);
249 if ((Status != STATUS_BUFFER_OVERFLOW) &&
250 (Status != STATUS_BUFFER_TOO_SMALL))
251 {
252 /* The key seems not present */
253 NT_ASSERT(!NT_SUCCESS(Status));
254 return Status;
255 }
256
257 /* Allocate a buffer */
258 ValueInformation = ExAllocatePoolWithTag(PagedPool, Length, TAG_VIDEO_PORT_BUFFER);
259 if (ValueInformation == NULL)
260 {
261 return Status;
262 }
263
264 /* Query the value */
265 Status = ZwQueryValueKey(SourceKeyHandle,
266 &ValueNameString,
267 KeyValuePartialInformation,
268 ValueInformation,
269 Length,
270 &Length);
271 if (!NT_SUCCESS(Status))
272 {
273 ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
274 return Status;
275 }
276
277 /* Write the registry value */
278 Status = ZwSetValueKey(DestKeyHandle,
279 &ValueNameString,
280 ValueInformation->TitleIndex,
281 ValueInformation->Type,
282 ValueInformation->Data,
283 ValueInformation->DataLength);
284
285 ExFreePoolWithTag(ValueInformation, TAG_VIDEO_PORT_BUFFER);
286
287 if (!NT_SUCCESS(Status))
288 {
289 ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
290 }
291
292 return Status;
293 }
294
295 NTSTATUS
296 NTAPI
IntSetupDeviceSettingsKey(PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)297 IntSetupDeviceSettingsKey(
298 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
299 {
300 static UNICODE_STRING SettingsKeyName = RTL_CONSTANT_STRING(L"Settings");
301 HANDLE DevInstRegKey, SourceKeyHandle, DestKeyHandle;
302 OBJECT_ATTRIBUTES ObjectAttributes;
303 NTSTATUS Status;
304
305 if (!DeviceExtension->PhysicalDeviceObject)
306 return STATUS_SUCCESS;
307
308 /* Open the software key: HKLM\System\CurrentControlSet\Control\Class\<ClassGUID>\<n> */
309 Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
310 PLUGPLAY_REGKEY_DRIVER,
311 KEY_ALL_ACCESS,
312 &DevInstRegKey);
313 if (Status != STATUS_SUCCESS)
314 {
315 ERR_(VIDEOPRT, "Failed to open device software key. Status 0x%lx\n", Status);
316 return Status;
317 }
318
319 /* Open the 'Settings' sub-key */
320 InitializeObjectAttributes(&ObjectAttributes,
321 &SettingsKeyName,
322 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
323 DevInstRegKey,
324 NULL);
325 Status = ZwOpenKey(&DestKeyHandle, KEY_WRITE, &ObjectAttributes);
326
327 /* Close the device software key */
328 ObCloseHandle(DevInstRegKey, KernelMode);
329
330 if (Status != STATUS_SUCCESS)
331 {
332 ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
333 return Status;
334 }
335
336 /* Open the device profile key */
337 InitializeObjectAttributes(&ObjectAttributes,
338 &DeviceExtension->RegistryPath,
339 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
340 NULL,
341 NULL);
342 Status = ZwOpenKey(&SourceKeyHandle, KEY_READ, &ObjectAttributes);
343 if (Status != STATUS_SUCCESS)
344 {
345 ERR_(VIDEOPRT, "ZwOpenKey failed for settings key: status 0x%lx\n", Status);
346 ObCloseHandle(DestKeyHandle, KernelMode);
347 return Status;
348 }
349
350 IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"InstalledDisplayDrivers");
351 IntCopyRegistryValue(SourceKeyHandle, DestKeyHandle, L"Attach.ToDesktop");
352
353 ObCloseHandle(SourceKeyHandle, KernelMode);
354 ObCloseHandle(DestKeyHandle, KernelMode);
355
356 return STATUS_SUCCESS;
357 }
358
359 NTSTATUS
IntDuplicateUnicodeString(IN ULONG Flags,IN PCUNICODE_STRING SourceString,OUT PUNICODE_STRING DestinationString)360 IntDuplicateUnicodeString(
361 IN ULONG Flags,
362 IN PCUNICODE_STRING SourceString,
363 OUT PUNICODE_STRING DestinationString)
364 {
365 if (SourceString == NULL ||
366 DestinationString == NULL ||
367 SourceString->Length > SourceString->MaximumLength ||
368 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
369 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
370 Flags >= 4)
371 {
372 return STATUS_INVALID_PARAMETER;
373 }
374
375 if ((SourceString->Length == 0) &&
376 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
377 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
378 {
379 DestinationString->Length = 0;
380 DestinationString->MaximumLength = 0;
381 DestinationString->Buffer = NULL;
382 }
383 else
384 {
385 USHORT DestMaxLength = SourceString->Length;
386
387 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
388 DestMaxLength += sizeof(UNICODE_NULL);
389
390 DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, TAG_VIDEO_PORT);
391 if (DestinationString->Buffer == NULL)
392 return STATUS_NO_MEMORY;
393
394 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
395 DestinationString->Length = SourceString->Length;
396 DestinationString->MaximumLength = DestMaxLength;
397
398 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
399 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
400 }
401
402 return STATUS_SUCCESS;
403 }
404
405 NTSTATUS
406 NTAPI
IntCreateNewRegistryPath(PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)407 IntCreateNewRegistryPath(
408 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension)
409 {
410 static UNICODE_STRING VideoIdValueName = RTL_CONSTANT_STRING(L"VideoId");
411 static UNICODE_STRING ControlVideoPathName =
412 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\");
413 HANDLE DevInstRegKey, SettingsKey, NewKey;
414 UCHAR VideoIdBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + GUID_STRING_LENGTH];
415 UNICODE_STRING VideoIdString;
416 UUID VideoId;
417 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation ;
418 NTSTATUS Status;
419 ULONG ResultLength;
420 USHORT KeyMaxLength;
421 OBJECT_ATTRIBUTES ObjectAttributes;
422 PWCHAR InstanceIdBuffer;
423
424 if (!DeviceExtension->PhysicalDeviceObject)
425 {
426 Status = IntDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
427 &DeviceExtension->RegistryPath,
428 &DeviceExtension->NewRegistryPath);
429 if (!NT_SUCCESS(Status))
430 ERR_(VIDEOPRT, "IntDuplicateUnicodeString() failed with status 0x%lx\n", Status);
431 return Status;
432 }
433
434 /* Open the hardware key: HKLM\System\CurrentControlSet\Enum\... */
435 Status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject,
436 PLUGPLAY_REGKEY_DEVICE,
437 KEY_ALL_ACCESS,
438 &DevInstRegKey);
439 if (Status != STATUS_SUCCESS)
440 {
441 ERR_(VIDEOPRT, "IoOpenDeviceRegistryKey failed: status 0x%lx\n", Status);
442 return Status;
443 }
444
445 /* Query the VideoId value */
446 ValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)VideoIdBuffer;
447 Status = ZwQueryValueKey(DevInstRegKey,
448 &VideoIdValueName,
449 KeyValuePartialInformation,
450 ValueInformation,
451 sizeof(VideoIdBuffer),
452 &ResultLength);
453 if (!NT_SUCCESS(Status))
454 {
455 /* Create a new video Id */
456 Status = ExUuidCreate(&VideoId);
457 if (!NT_SUCCESS(Status))
458 {
459 ERR_(VIDEOPRT, "ExUuidCreate failed: status 0x%lx\n", Status);
460 ObCloseHandle(DevInstRegKey, KernelMode);
461 return Status;
462 }
463
464 /* Convert the GUID into a string */
465 Status = RtlStringFromGUID(&VideoId, &VideoIdString);
466 if (!NT_SUCCESS(Status))
467 {
468 ERR_(VIDEOPRT, "RtlStringFromGUID failed: status 0x%lx\n", Status);
469 ObCloseHandle(DevInstRegKey, KernelMode);
470 return Status;
471 }
472
473 /* Copy the GUID String to our buffer */
474 ValueInformation->DataLength = min(VideoIdString.Length, GUID_STRING_LENGTH);
475 RtlCopyMemory(ValueInformation->Data,
476 VideoIdString.Buffer,
477 ValueInformation->DataLength);
478
479 /* Free the GUID string */
480 RtlFreeUnicodeString(&VideoIdString);
481
482 /* Write the VideoId registry value */
483 Status = ZwSetValueKey(DevInstRegKey,
484 &VideoIdValueName,
485 0,
486 REG_SZ,
487 ValueInformation->Data,
488 ValueInformation->DataLength);
489 if (!NT_SUCCESS(Status))
490 {
491 ERR_(VIDEOPRT, "ZwSetValueKey failed: status 0x%lx\n", Status);
492 ObCloseHandle(DevInstRegKey, KernelMode);
493 return Status;
494 }
495 }
496
497 /* Initialize the VideoId string from the registry data */
498 VideoIdString.Buffer = (PWCHAR)ValueInformation->Data;
499 VideoIdString.Length = (USHORT)ValueInformation->DataLength;
500 VideoIdString.MaximumLength = VideoIdString.Length;
501
502 /* Close the hardware key */
503 ObCloseHandle(DevInstRegKey, KernelMode);
504
505 /* Calculate the size needed for the new registry path name */
506 KeyMaxLength = ControlVideoPathName.Length +
507 VideoIdString.Length +
508 sizeof(L"\\0000");
509
510 /* Allocate the path name buffer */
511 DeviceExtension->NewRegistryPath.Length = 0;
512 DeviceExtension->NewRegistryPath.MaximumLength = KeyMaxLength;
513 DeviceExtension->NewRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
514 KeyMaxLength,
515 TAG_VIDEO_PORT);
516 if (DeviceExtension->NewRegistryPath.Buffer == NULL)
517 {
518 ERR_(VIDEOPRT, "Failed to allocate key name buffer.\n");
519 return STATUS_INSUFFICIENT_RESOURCES;
520 }
521
522 /* Copy the root key name and append the VideoId string */
523 RtlCopyUnicodeString(&DeviceExtension->NewRegistryPath,
524 &ControlVideoPathName);
525 RtlAppendUnicodeStringToString(&DeviceExtension->NewRegistryPath,
526 &VideoIdString);
527
528 /* Check if we have the key already */
529 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
530 DeviceExtension->NewRegistryPath.Buffer);
531 if (Status != STATUS_SUCCESS)
532 {
533 /* Try to create the new key */
534 Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
535 DeviceExtension->NewRegistryPath.Buffer);
536 }
537
538 /* Append a the instance path */ /// \todo HACK
539 RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"\\");
540 InstanceIdBuffer = DeviceExtension->NewRegistryPath.Buffer +
541 DeviceExtension->NewRegistryPath.Length / sizeof(WCHAR);
542 RtlAppendUnicodeToString(&DeviceExtension->NewRegistryPath, L"0000");
543
544 /* Write instance ID */
545 swprintf(InstanceIdBuffer, L"%04u", DeviceExtension->DisplayNumber);
546
547 /* Check if the name exists */
548 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
549 DeviceExtension->NewRegistryPath.Buffer);
550 if (Status != STATUS_SUCCESS)
551 {
552 /* Try to create the new key */
553 Status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
554 DeviceExtension->NewRegistryPath.Buffer);
555 if (!NT_SUCCESS(Status))
556 {
557 ERR_(VIDEOPRT, "Failed create key '%wZ'\n", &DeviceExtension->NewRegistryPath);
558 return Status;
559 }
560
561 /* Open the new key */
562 InitializeObjectAttributes(&ObjectAttributes,
563 &DeviceExtension->NewRegistryPath,
564 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
565 NULL,
566 NULL);
567 Status = ZwOpenKey(&NewKey, KEY_WRITE, &ObjectAttributes);
568 if (!NT_SUCCESS(Status))
569 {
570 ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
571 return Status;
572 }
573
574 /* Open the device profile key */
575 InitializeObjectAttributes(&ObjectAttributes,
576 &DeviceExtension->RegistryPath,
577 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
578 NULL,
579 NULL);
580 Status = ZwOpenKey(&SettingsKey, KEY_READ, &ObjectAttributes);
581 if (!NT_SUCCESS(Status))
582 {
583 ERR_(VIDEOPRT, "Failed to open settings key. Status 0x%lx\n", Status);
584 ObCloseHandle(NewKey, KernelMode);
585 return Status;
586 }
587
588 /* Copy the registry data from the legacy key */
589 Status = IntCopyRegistryKey(SettingsKey, NewKey);
590
591 /* Close the key handles */
592 ObCloseHandle(SettingsKey, KernelMode);
593 ObCloseHandle(NewKey, KernelMode);
594 }
595
596 return Status;
597 }
598
599 NTSTATUS
600 NTAPI
IntCreateRegistryPath(IN PCUNICODE_STRING DriverRegistryPath,IN ULONG DeviceNumber,OUT PUNICODE_STRING DeviceRegistryPath)601 IntCreateRegistryPath(
602 IN PCUNICODE_STRING DriverRegistryPath,
603 IN ULONG DeviceNumber,
604 OUT PUNICODE_STRING DeviceRegistryPath)
605 {
606 static WCHAR RegistryMachineSystem[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\";
607 static WCHAR CurrentControlSet[] = L"CURRENTCONTROLSET\\";
608 static WCHAR ControlSet[] = L"CONTROLSET";
609 static WCHAR Insert1[] = L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
610 static WCHAR Insert2[] = L"\\Device";
611 UNICODE_STRING DeviceNumberString;
612 WCHAR DeviceNumberBuffer[20];
613 BOOLEAN Valid;
614 UNICODE_STRING AfterControlSet;
615 NTSTATUS Status;
616
617 AfterControlSet = *DriverRegistryPath;
618
619 /* Convert DeviceNumber to string */
620 DeviceNumberString.Length = 0;
621 DeviceNumberString.MaximumLength = sizeof(DeviceNumberBuffer);
622 DeviceNumberString.Buffer = DeviceNumberBuffer;
623 Status = RtlIntegerToUnicodeString(DeviceNumber, 10, &DeviceNumberString);
624 if (!NT_SUCCESS(Status))
625 {
626 ERR_(VIDEOPRT, "RtlIntegerToUnicodeString(%u) returned 0x%08x\n", DeviceNumber, Status);
627 return Status;
628 }
629
630 /* Check if path begins with \\REGISTRY\\MACHINE\\SYSTEM\\ */
631 Valid = (DriverRegistryPath->Length > sizeof(RegistryMachineSystem) &&
632 0 == _wcsnicmp(DriverRegistryPath->Buffer, RegistryMachineSystem,
633 wcslen(RegistryMachineSystem)));
634 if (Valid)
635 {
636 AfterControlSet.Buffer += wcslen(RegistryMachineSystem);
637 AfterControlSet.Length -= sizeof(RegistryMachineSystem) - sizeof(UNICODE_NULL);
638
639 /* Check if path contains CURRENTCONTROLSET */
640 if (AfterControlSet.Length > sizeof(CurrentControlSet) &&
641 0 == _wcsnicmp(AfterControlSet.Buffer, CurrentControlSet, wcslen(CurrentControlSet)))
642 {
643 AfterControlSet.Buffer += wcslen(CurrentControlSet);
644 AfterControlSet.Length -= sizeof(CurrentControlSet) - sizeof(UNICODE_NULL);
645 }
646 /* Check if path contains CONTROLSETnum */
647 else if (AfterControlSet.Length > sizeof(ControlSet) &&
648 0 == _wcsnicmp(AfterControlSet.Buffer, ControlSet, wcslen(ControlSet)))
649 {
650 AfterControlSet.Buffer += wcslen(ControlSet);
651 AfterControlSet.Length -= sizeof(ControlSet) - sizeof(UNICODE_NULL);
652 while (AfterControlSet.Length > 0 &&
653 *AfterControlSet.Buffer >= L'0' &&
654 *AfterControlSet.Buffer <= L'9')
655 {
656 AfterControlSet.Buffer++;
657 AfterControlSet.Length -= sizeof(WCHAR);
658 }
659
660 Valid = (AfterControlSet.Length > 0 && L'\\' == *AfterControlSet.Buffer);
661 AfterControlSet.Buffer++;
662 AfterControlSet.Length -= sizeof(WCHAR);
663 AfterControlSet.MaximumLength = AfterControlSet.Length;
664 }
665 else
666 {
667 Valid = FALSE;
668 }
669 }
670
671 if (!VideoPortUseNewKey)
672 {
673 INFO_(VIDEOPRT, "Using old registry key as 'UseNewKey' is FALSE\n");
674 Valid = FALSE;
675 }
676 else if (Valid)
677 {
678 DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert1) + sizeof(Insert2)
679 + DeviceNumberString.Length;
680 DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(PagedPool,
681 DeviceRegistryPath->MaximumLength,
682 TAG_VIDEO_PORT);
683 if (DeviceRegistryPath->Buffer != NULL)
684 {
685 /* Build device path */
686 wcsncpy(DeviceRegistryPath->Buffer,
687 DriverRegistryPath->Buffer,
688 AfterControlSet.Buffer - DriverRegistryPath->Buffer);
689 DeviceRegistryPath->Length = (AfterControlSet.Buffer - DriverRegistryPath->Buffer) * sizeof(WCHAR);
690 RtlAppendUnicodeToString(DeviceRegistryPath, Insert1);
691 RtlAppendUnicodeStringToString(DeviceRegistryPath, &AfterControlSet);
692 RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
693 RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
694
695 /* Check if registry key exists */
696 Valid = NT_SUCCESS(RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, DeviceRegistryPath->Buffer));
697
698 if (!Valid)
699 ExFreePoolWithTag(DeviceRegistryPath->Buffer, TAG_VIDEO_PORT);
700 }
701 else
702 {
703 Valid = FALSE;
704 }
705 }
706 else
707 {
708 WARN_(VIDEOPRT, "Unparsable registry path %wZ\n", DriverRegistryPath);
709 }
710
711 /* If path doesn't point to *ControlSet*, use DriverRegistryPath directly */
712 if (!Valid)
713 {
714 DeviceRegistryPath->MaximumLength = DriverRegistryPath->Length + sizeof(Insert2) + DeviceNumberString.Length;
715 DeviceRegistryPath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
716 DeviceRegistryPath->MaximumLength,
717 TAG_VIDEO_PORT);
718
719 if (!DeviceRegistryPath->Buffer)
720 return STATUS_NO_MEMORY;
721
722 RtlCopyUnicodeString(DeviceRegistryPath, DriverRegistryPath);
723 RtlAppendUnicodeToString(DeviceRegistryPath, Insert2);
724 RtlAppendUnicodeStringToString(DeviceRegistryPath, &DeviceNumberString);
725 }
726
727 DPRINT("Formatted registry key '%wZ' -> '%wZ'\n",
728 DriverRegistryPath, DeviceRegistryPath);
729
730 return STATUS_SUCCESS;
731 }
732