[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / deviface.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/deviface.c
5 * PURPOSE: Device interface functions
6 *
7 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
8 * Matthew Brace (ismarc@austin.rr.com)
9 * Hervé Poussineau (hpoussin@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
22
23 static
24 NTSTATUS
25 OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,
26 IN ACCESS_MASK DesiredAccess,
27 IN OPTIONAL PHANDLE GuidKey,
28 IN OPTIONAL PHANDLE DeviceKey,
29 IN OPTIONAL PHANDLE InstanceKey)
30 {
31 OBJECT_ATTRIBUTES ObjectAttributes;
32 WCHAR PathBuffer[MAX_PATH];
33 UNICODE_STRING BaseKeyU;
34 UNICODE_STRING GuidString, SubKeyName, ReferenceString;
35 PWCHAR StartPosition, EndPosition;
36 HANDLE ClassesKey;
37 PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP;
38 HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal;
39 NTSTATUS Status;
40
41 SubKeyName.Buffer = NULL;
42
43 if (GuidKey != NULL)
44 GuidKeyRealP = GuidKey;
45 else
46 GuidKeyRealP = &GuidKeyReal;
47
48 if (DeviceKey != NULL)
49 DeviceKeyRealP = DeviceKey;
50 else
51 DeviceKeyRealP = &DeviceKeyReal;
52
53 if (InstanceKey != NULL)
54 InstanceKeyRealP = InstanceKey;
55 else
56 InstanceKeyRealP = &InstanceKeyReal;
57
58 *GuidKeyRealP = INVALID_HANDLE_VALUE;
59 *DeviceKeyRealP = INVALID_HANDLE_VALUE;
60 *InstanceKeyRealP = INVALID_HANDLE_VALUE;
61
62 BaseKeyU.Buffer = PathBuffer;
63 BaseKeyU.Length = 0;
64 BaseKeyU.MaximumLength = MAX_PATH * sizeof(WCHAR);
65
66 RtlAppendUnicodeToString(&BaseKeyU, BaseKeyString);
67
68 /* Open the DeviceClasses key */
69 InitializeObjectAttributes(&ObjectAttributes,
70 &BaseKeyU,
71 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
72 NULL,
73 NULL);
74 Status = ZwOpenKey(&ClassesKey,
75 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
76 &ObjectAttributes);
77 if (!NT_SUCCESS(Status))
78 {
79 DPRINT1("Failed to open %wZ\n", &BaseKeyU);
80 goto cleanup;
81 }
82
83 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
84 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
85 if (!StartPosition || !EndPosition || StartPosition > EndPosition)
86 {
87 DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName);
88 return STATUS_INVALID_PARAMETER_1;
89 }
90 GuidString.Buffer = StartPosition;
91 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
92
93 InitializeObjectAttributes(&ObjectAttributes,
94 &GuidString,
95 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
96 ClassesKey,
97 NULL);
98 Status = ZwOpenKey(GuidKeyRealP,
99 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
100 &ObjectAttributes);
101 ZwClose(ClassesKey);
102 if (!NT_SUCCESS(Status))
103 {
104 DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString, Status);
105 goto cleanup;
106 }
107
108 SubKeyName.Buffer = ExAllocatePool(PagedPool, SymbolicLinkName->Length);
109 if (!SubKeyName.Buffer)
110 {
111 Status = STATUS_INSUFFICIENT_RESOURCES;
112 goto cleanup;
113 }
114 SubKeyName.MaximumLength = SymbolicLinkName->Length;
115 SubKeyName.Length = 0;
116
117 RtlAppendUnicodeStringToString(&SubKeyName,
118 SymbolicLinkName);
119
120 SubKeyName.Buffer[0] = L'#';
121 SubKeyName.Buffer[1] = L'#';
122 SubKeyName.Buffer[2] = L'?';
123 SubKeyName.Buffer[3] = L'#';
124
125 ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\');
126 if (ReferenceString.Buffer != NULL)
127 {
128 ReferenceString.Buffer[0] = L'#';
129
130 SubKeyName.Length = ReferenceString.Buffer - SubKeyName.Buffer;
131 ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length;
132 }
133 else
134 {
135 RtlInitUnicodeString(&ReferenceString, L"#");
136 }
137
138 InitializeObjectAttributes(&ObjectAttributes,
139 &SubKeyName,
140 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
141 *GuidKeyRealP,
142 NULL);
143 Status = ZwOpenKey(DeviceKeyRealP,
144 DesiredAccess | KEY_ENUMERATE_SUB_KEYS,
145 &ObjectAttributes);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU, &GuidString, &SubKeyName);
149 goto cleanup;
150 }
151
152 InitializeObjectAttributes(&ObjectAttributes,
153 &ReferenceString,
154 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
155 *DeviceKeyRealP,
156 NULL);
157 Status = ZwOpenKey(InstanceKeyRealP,
158 DesiredAccess,
159 &ObjectAttributes);
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU, &GuidString, &SubKeyName, &ReferenceString, Status);
163 goto cleanup;
164 }
165
166 Status = STATUS_SUCCESS;
167
168 cleanup:
169 if (SubKeyName.Buffer != NULL)
170 ExFreePool(SubKeyName.Buffer);
171
172 if (NT_SUCCESS(Status))
173 {
174 if (!GuidKey)
175 ZwClose(*GuidKeyRealP);
176
177 if (!DeviceKey)
178 ZwClose(*DeviceKeyRealP);
179
180 if (!InstanceKey)
181 ZwClose(*InstanceKeyRealP);
182 }
183 else
184 {
185 if (*GuidKeyRealP != INVALID_HANDLE_VALUE)
186 ZwClose(*GuidKeyRealP);
187
188 if (*DeviceKeyRealP != INVALID_HANDLE_VALUE)
189 ZwClose(*DeviceKeyRealP);
190
191 if (*InstanceKeyRealP != INVALID_HANDLE_VALUE)
192 ZwClose(*InstanceKeyRealP);
193 }
194
195 return Status;
196 }
197 /*++
198 * @name IoOpenDeviceInterfaceRegistryKey
199 * @unimplemented
200 *
201 * Provides a handle to the device's interface instance registry key.
202 * Documented in WDK.
203 *
204 * @param SymbolicLinkName
205 * Pointer to a string which identifies the device interface instance
206 *
207 * @param DesiredAccess
208 * Desired ACCESS_MASK used to access the key (like KEY_READ,
209 * KEY_WRITE, etc)
210 *
211 * @param DeviceInterfaceKey
212 * If a call has been succesfull, a handle to the registry key
213 * will be stored there
214 *
215 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
216 * otherwise (see WDK for details)
217 *
218 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
219 *
220 *--*/
221 NTSTATUS
222 NTAPI
223 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName,
224 IN ACCESS_MASK DesiredAccess,
225 OUT PHANDLE DeviceInterfaceKey)
226 {
227 WCHAR StrBuff[MAX_PATH], PathBuff[MAX_PATH];
228 PWCHAR Guid, RefString;
229 UNICODE_STRING DevParamU = RTL_CONSTANT_STRING(L"\\Device Parameters");
230 UNICODE_STRING PrefixU = RTL_CONSTANT_STRING(L"\\??\\");
231 UNICODE_STRING KeyPath, KeyName;
232 UNICODE_STRING MatchableGuid;
233 UNICODE_STRING GuidString;
234 HANDLE GuidKey, hInterfaceKey;
235 ULONG Index = 0;
236 PKEY_BASIC_INFORMATION KeyInformation;
237 ULONG KeyInformationLength;
238 OBJECT_ATTRIBUTES ObjectAttributes;
239 NTSTATUS Status;
240 ULONG RequiredLength;
241
242 swprintf(StrBuff, L"##?#%s", &SymbolicLinkName->Buffer[PrefixU.Length / sizeof(WCHAR)]);
243
244 RefString = wcsstr(StrBuff, L"\\");
245 if (RefString)
246 {
247 RefString[0] = 0;
248 }
249
250 RtlInitUnicodeString(&MatchableGuid, StrBuff);
251
252 Guid = wcsstr(StrBuff, L"{");
253 if (!Guid)
254 return STATUS_OBJECT_NAME_NOT_FOUND;
255
256 KeyPath.Buffer = PathBuff;
257 KeyPath.Length = 0;
258 KeyPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
259
260 GuidString.Buffer = Guid;
261 GuidString.Length = GuidString.MaximumLength = 38 * sizeof(WCHAR);
262
263 RtlAppendUnicodeToString(&KeyPath, BaseKeyString);
264 RtlAppendUnicodeStringToString(&KeyPath, &GuidString);
265
266 InitializeObjectAttributes(&ObjectAttributes,
267 &KeyPath,
268 OBJ_CASE_INSENSITIVE,
269 0,
270 NULL);
271
272 Status = ZwOpenKey(&GuidKey, KEY_CREATE_SUB_KEY, &ObjectAttributes);
273 if (!NT_SUCCESS(Status))
274 return Status;
275
276 while (TRUE)
277 {
278 Status = ZwEnumerateKey(GuidKey,
279 Index,
280 KeyBasicInformation,
281 NULL,
282 0,
283 &RequiredLength);
284 if (Status == STATUS_NO_MORE_ENTRIES)
285 break;
286 else if (Status == STATUS_BUFFER_TOO_SMALL)
287 {
288 KeyInformationLength = RequiredLength;
289 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
290 if (!KeyInformation)
291 {
292 ZwClose(GuidKey);
293 return STATUS_INSUFFICIENT_RESOURCES;
294 }
295
296 Status = ZwEnumerateKey(GuidKey,
297 Index,
298 KeyBasicInformation,
299 KeyInformation,
300 KeyInformationLength,
301 &RequiredLength);
302 }
303 else
304 {
305 ZwClose(GuidKey);
306 return STATUS_OBJECT_PATH_NOT_FOUND;
307 }
308 Index++;
309
310 if (!NT_SUCCESS(Status))
311 {
312 ZwClose(GuidKey);
313 return Status;
314 }
315
316 KeyName.Length = KeyName.MaximumLength = KeyInformation->NameLength;
317 KeyName.Buffer = KeyInformation->Name;
318
319 if (!RtlEqualUnicodeString(&KeyName, &MatchableGuid, TRUE))
320 {
321 ExFreePool(KeyInformation);
322 continue;
323 }
324
325 KeyPath.Length = 0;
326 RtlAppendUnicodeStringToString(&KeyPath, &KeyName);
327 RtlAppendUnicodeToString(&KeyPath, L"\\");
328
329 /* check for presence of a reference string */
330 if (RefString)
331 {
332 /* append reference string */
333 RefString[0] = L'#';
334 RtlInitUnicodeString(&KeyName, RefString);
335 }
336 else
337 {
338 /* no reference string */
339 RtlInitUnicodeString(&KeyName, L"#");
340 }
341 RtlAppendUnicodeStringToString(&KeyPath, &KeyName);
342
343 /* initialize reference string attributes */
344 InitializeObjectAttributes(&ObjectAttributes,
345 &KeyPath,
346 OBJ_CASE_INSENSITIVE,
347 GuidKey,
348 NULL);
349
350 /* now open device interface key */
351 Status = ZwOpenKey(&hInterfaceKey, KEY_CREATE_SUB_KEY, &ObjectAttributes);
352
353 if (NT_SUCCESS(Status))
354 {
355 /* check if it provides a DeviceParameters key */
356 InitializeObjectAttributes(&ObjectAttributes, &DevParamU, OBJ_CASE_INSENSITIVE, hInterfaceKey, NULL);
357
358 Status = ZwCreateKey(DeviceInterfaceKey, DesiredAccess, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
359
360 if (NT_SUCCESS(Status))
361 {
362 /* DeviceParameters key present */
363 ZwClose(hInterfaceKey);
364 }
365 else
366 {
367 /* fall back to device interface */
368 *DeviceInterfaceKey = hInterfaceKey;
369 Status = STATUS_SUCCESS;
370 }
371 }
372
373 /* close class key */
374 ZwClose(GuidKey);
375 ExFreePool(KeyInformation);
376 return Status;
377 }
378
379 return STATUS_OBJECT_PATH_NOT_FOUND;
380 }
381
382 /*++
383 * @name IoGetDeviceInterfaceAlias
384 * @unimplemented
385 *
386 * Returns the alias device interface of the specified device interface
387 * instance, if the alias exists.
388 * Documented in WDK.
389 *
390 * @param SymbolicLinkName
391 * Pointer to a string which identifies the device interface instance
392 *
393 * @param AliasInterfaceClassGuid
394 * See WDK
395 *
396 * @param AliasSymbolicLinkName
397 * See WDK
398 *
399 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
400 * otherwise (see WDK for details)
401 *
402 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
403 *
404 *--*/
405 NTSTATUS
406 NTAPI
407 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName,
408 IN CONST GUID *AliasInterfaceClassGuid,
409 OUT PUNICODE_STRING AliasSymbolicLinkName)
410 {
411 return STATUS_NOT_IMPLEMENTED;
412 }
413
414 /*++
415 * @name IopOpenInterfaceKey
416 *
417 * Returns the alias device interface of the specified device interface
418 *
419 * @param InterfaceClassGuid
420 * FILLME
421 *
422 * @param DesiredAccess
423 * FILLME
424 *
425 * @param pInterfaceKey
426 * FILLME
427 *
428 * @return Usual NTSTATUS
429 *
430 * @remarks None
431 *
432 *--*/
433 static NTSTATUS
434 IopOpenInterfaceKey(IN CONST GUID *InterfaceClassGuid,
435 IN ACCESS_MASK DesiredAccess,
436 OUT HANDLE *pInterfaceKey)
437 {
438 UNICODE_STRING LocalMachine = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\");
439 UNICODE_STRING GuidString;
440 UNICODE_STRING KeyName;
441 OBJECT_ATTRIBUTES ObjectAttributes;
442 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
443 NTSTATUS Status;
444
445 GuidString.Buffer = KeyName.Buffer = NULL;
446
447 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
451 goto cleanup;
452 }
453
454 KeyName.Length = 0;
455 KeyName.MaximumLength = LocalMachine.Length + (wcslen(REGSTR_PATH_DEVICE_CLASSES) + 1) * sizeof(WCHAR) + GuidString.Length;
456 KeyName.Buffer = ExAllocatePool(PagedPool, KeyName.MaximumLength);
457 if (!KeyName.Buffer)
458 {
459 DPRINT("ExAllocatePool() failed\n");
460 Status = STATUS_INSUFFICIENT_RESOURCES;
461 goto cleanup;
462 }
463
464 Status = RtlAppendUnicodeStringToString(&KeyName, &LocalMachine);
465 if (!NT_SUCCESS(Status))
466 {
467 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
468 goto cleanup;
469 }
470 Status = RtlAppendUnicodeToString(&KeyName, REGSTR_PATH_DEVICE_CLASSES);
471 if (!NT_SUCCESS(Status))
472 {
473 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
474 goto cleanup;
475 }
476 Status = RtlAppendUnicodeToString(&KeyName, L"\\");
477 if (!NT_SUCCESS(Status))
478 {
479 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
480 goto cleanup;
481 }
482 Status = RtlAppendUnicodeStringToString(&KeyName, &GuidString);
483 if (!NT_SUCCESS(Status))
484 {
485 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
486 goto cleanup;
487 }
488
489 InitializeObjectAttributes(
490 &ObjectAttributes,
491 &KeyName,
492 OBJ_CASE_INSENSITIVE,
493 NULL,
494 NULL);
495 Status = ZwOpenKey(
496 &InterfaceKey,
497 DesiredAccess,
498 &ObjectAttributes);
499 if (!NT_SUCCESS(Status))
500 {
501 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
502 goto cleanup;
503 }
504
505 *pInterfaceKey = InterfaceKey;
506 Status = STATUS_SUCCESS;
507
508 cleanup:
509 if (!NT_SUCCESS(Status))
510 {
511 if (InterfaceKey != INVALID_HANDLE_VALUE)
512 ZwClose(InterfaceKey);
513 }
514 RtlFreeUnicodeString(&GuidString);
515 RtlFreeUnicodeString(&KeyName);
516 return Status;
517 }
518
519 /*++
520 * @name IoGetDeviceInterfaces
521 * @implemented
522 *
523 * Returns a list of device interfaces of a particular device interface class.
524 * Documented in WDK
525 *
526 * @param InterfaceClassGuid
527 * Points to a class GUID specifying the device interface class
528 *
529 * @param PhysicalDeviceObject
530 * Points to an optional PDO that narrows the search to only the
531 * device interfaces of the device represented by the PDO
532 *
533 * @param Flags
534 * Specifies flags that modify the search for device interfaces. The
535 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
536 * returned symbolic links should contain also disabled device
537 * interfaces in addition to the enabled ones.
538 *
539 * @param SymbolicLinkList
540 * Points to a character pointer that is filled in on successful return
541 * with a list of unicode strings identifying the device interfaces
542 * that match the search criteria. The newly allocated buffer contains
543 * a list of symbolic link names. Each unicode string in the list is
544 * null-terminated; the end of the whole list is marked by an additional
545 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
546 * when it is no longer needed.
547 * If no device interfaces match the search criteria, this routine
548 * returns STATUS_SUCCESS and the string contains a single NULL
549 * character.
550 *
551 * @return Usual NTSTATUS
552 *
553 * @remarks None
554 *
555 *--*/
556 NTSTATUS
557 NTAPI
558 IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid,
559 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
560 IN ULONG Flags,
561 OUT PWSTR *SymbolicLinkList)
562 {
563 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
564 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
565 HANDLE InterfaceKey = INVALID_HANDLE_VALUE;
566 HANDLE DeviceKey = INVALID_HANDLE_VALUE;
567 HANDLE ReferenceKey = INVALID_HANDLE_VALUE;
568 HANDLE ControlKey = INVALID_HANDLE_VALUE;
569 PKEY_BASIC_INFORMATION DeviceBi = NULL;
570 PKEY_BASIC_INFORMATION ReferenceBi = NULL;
571 PKEY_VALUE_PARTIAL_INFORMATION bip = NULL;
572 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
573 UNICODE_STRING KeyName;
574 OBJECT_ATTRIBUTES ObjectAttributes;
575 BOOLEAN FoundRightPDO = FALSE;
576 ULONG i = 0, j, Size, NeededLength, ActualLength, LinkedValue;
577 UNICODE_STRING ReturnBuffer = { 0, 0, NULL };
578 NTSTATUS Status;
579
580 PAGED_CODE();
581
582 Status = IopOpenInterfaceKey(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, &InterfaceKey);
583 if (!NT_SUCCESS(Status))
584 {
585 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status);
586 goto cleanup;
587 }
588
589 /* Enumerate subkeys (ie the different device objets) */
590 while (TRUE)
591 {
592 Status = ZwEnumerateKey(
593 InterfaceKey,
594 i,
595 KeyBasicInformation,
596 NULL,
597 0,
598 &Size);
599 if (Status == STATUS_NO_MORE_ENTRIES)
600 {
601 break;
602 }
603 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
604 {
605 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
606 goto cleanup;
607 }
608
609 DeviceBi = ExAllocatePool(PagedPool, Size);
610 if (!DeviceBi)
611 {
612 DPRINT("ExAllocatePool() failed\n");
613 Status = STATUS_INSUFFICIENT_RESOURCES;
614 goto cleanup;
615 }
616 Status = ZwEnumerateKey(
617 InterfaceKey,
618 i++,
619 KeyBasicInformation,
620 DeviceBi,
621 Size,
622 &Size);
623 if (!NT_SUCCESS(Status))
624 {
625 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
626 goto cleanup;
627 }
628
629 /* Open device key */
630 KeyName.Length = KeyName.MaximumLength = (USHORT)DeviceBi->NameLength;
631 KeyName.Buffer = DeviceBi->Name;
632 InitializeObjectAttributes(
633 &ObjectAttributes,
634 &KeyName,
635 OBJ_CASE_INSENSITIVE,
636 InterfaceKey,
637 NULL);
638 Status = ZwOpenKey(
639 &DeviceKey,
640 KEY_ENUMERATE_SUB_KEYS,
641 &ObjectAttributes);
642 if (!NT_SUCCESS(Status))
643 {
644 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
645 goto cleanup;
646 }
647
648 if (PhysicalDeviceObject)
649 {
650 /* Check if we are on the right physical device object,
651 * by reading the DeviceInstance string
652 */
653 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
654 //FoundRightPDO = TRUE;
655 Status = STATUS_NOT_IMPLEMENTED;
656 goto cleanup;
657 }
658
659 /* Enumerate subkeys (ie the different reference strings) */
660 j = 0;
661 while (TRUE)
662 {
663 Status = ZwEnumerateKey(
664 DeviceKey,
665 j,
666 KeyBasicInformation,
667 NULL,
668 0,
669 &Size);
670 if (Status == STATUS_NO_MORE_ENTRIES)
671 {
672 break;
673 }
674 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
675 {
676 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
677 goto cleanup;
678 }
679
680 ReferenceBi = ExAllocatePool(PagedPool, Size);
681 if (!ReferenceBi)
682 {
683 DPRINT("ExAllocatePool() failed\n");
684 Status = STATUS_INSUFFICIENT_RESOURCES;
685 goto cleanup;
686 }
687 Status = ZwEnumerateKey(
688 DeviceKey,
689 j++,
690 KeyBasicInformation,
691 ReferenceBi,
692 Size,
693 &Size);
694 if (!NT_SUCCESS(Status))
695 {
696 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
697 goto cleanup;
698 }
699
700 KeyName.Length = KeyName.MaximumLength = (USHORT)ReferenceBi->NameLength;
701 KeyName.Buffer = ReferenceBi->Name;
702 if (RtlEqualUnicodeString(&KeyName, &Control, TRUE))
703 {
704 /* Skip Control subkey */
705 goto NextReferenceString;
706 }
707
708 /* Open reference key */
709 InitializeObjectAttributes(
710 &ObjectAttributes,
711 &KeyName,
712 OBJ_CASE_INSENSITIVE,
713 DeviceKey,
714 NULL);
715 Status = ZwOpenKey(
716 &ReferenceKey,
717 KEY_QUERY_VALUE,
718 &ObjectAttributes);
719 if (!NT_SUCCESS(Status))
720 {
721 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
722 goto cleanup;
723 }
724
725 if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE))
726 {
727 /* We have to check if the interface is enabled, by
728 * reading the Linked value in the Control subkey
729 */
730 InitializeObjectAttributes(
731 &ObjectAttributes,
732 &Control,
733 OBJ_CASE_INSENSITIVE,
734 ReferenceKey,
735 NULL);
736 Status = ZwOpenKey(
737 &ControlKey,
738 KEY_QUERY_VALUE,
739 &ObjectAttributes);
740 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
741 {
742 /* That's OK. The key doesn't exist (yet) because
743 * the interface is not activated.
744 */
745 goto NextReferenceString;
746 }
747 else if (!NT_SUCCESS(Status))
748 {
749 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
750 goto cleanup;
751 }
752
753 RtlInitUnicodeString(&KeyName, L"Linked");
754 Status = ZwQueryValueKey(ControlKey,
755 &KeyName,
756 KeyValuePartialInformation,
757 NULL,
758 0,
759 &NeededLength);
760 if (Status == STATUS_BUFFER_TOO_SMALL)
761 {
762 ActualLength = NeededLength;
763 PartialInfo = ExAllocatePool(NonPagedPool, ActualLength);
764 if (!PartialInfo)
765 {
766 Status = STATUS_INSUFFICIENT_RESOURCES;
767 goto cleanup;
768 }
769
770 Status = ZwQueryValueKey(ControlKey,
771 &KeyName,
772 KeyValuePartialInformation,
773 PartialInfo,
774 ActualLength,
775 &NeededLength);
776 if (!NT_SUCCESS(Status))
777 {
778 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status);
779 ExFreePool(PartialInfo);
780 goto cleanup;
781 }
782
783 if (PartialInfo->Type != REG_DWORD || PartialInfo->DataLength != sizeof(ULONG))
784 {
785 DPRINT1("Bad registry read\n");
786 ExFreePool(PartialInfo);
787 goto cleanup;
788 }
789
790 RtlCopyMemory(&LinkedValue,
791 PartialInfo->Data,
792 PartialInfo->DataLength);
793
794 ExFreePool(PartialInfo);
795 if (LinkedValue == 0)
796 {
797 /* This interface isn't active */
798 goto NextReferenceString;
799 }
800 }
801 else
802 {
803 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status);
804 goto cleanup;
805 }
806 }
807
808 /* Read the SymbolicLink string and add it into SymbolicLinkList */
809 Status = ZwQueryValueKey(
810 ReferenceKey,
811 &SymbolicLink,
812 KeyValuePartialInformation,
813 NULL,
814 0,
815 &Size);
816 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
817 {
818 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
819 goto cleanup;
820 }
821 bip = ExAllocatePool(PagedPool, Size);
822 if (!bip)
823 {
824 DPRINT("ExAllocatePool() failed\n");
825 Status = STATUS_INSUFFICIENT_RESOURCES;
826 goto cleanup;
827 }
828 Status = ZwQueryValueKey(
829 ReferenceKey,
830 &SymbolicLink,
831 KeyValuePartialInformation,
832 bip,
833 Size,
834 &Size);
835 if (!NT_SUCCESS(Status))
836 {
837 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
838 goto cleanup;
839 }
840 else if (bip->Type != REG_SZ)
841 {
842 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip->Type, REG_SZ);
843 Status = STATUS_UNSUCCESSFUL;
844 goto cleanup;
845 }
846 else if (bip->DataLength < 5 * sizeof(WCHAR))
847 {
848 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip->DataLength < 5 * sizeof(WCHAR));
849 Status = STATUS_UNSUCCESSFUL;
850 goto cleanup;
851 }
852 KeyName.Length = KeyName.MaximumLength = (USHORT)bip->DataLength - 4 * sizeof(WCHAR);
853 KeyName.Buffer = &((PWSTR)bip->Data)[4];
854 if (KeyName.Length && KeyName.Buffer[KeyName.Length / sizeof(WCHAR)] == UNICODE_NULL)
855 {
856 /* Remove trailing NULL */
857 KeyName.Length -= sizeof(WCHAR);
858 }
859
860 /* Add new symbolic link to symbolic link list */
861 if (ReturnBuffer.Length + KeyName.Length + sizeof(WCHAR) > ReturnBuffer.MaximumLength)
862 {
863 PWSTR NewBuffer;
864 ReturnBuffer.MaximumLength = max(ReturnBuffer.MaximumLength * 2, ReturnBuffer.Length + KeyName.Length + 2 * sizeof(WCHAR));
865 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
866 if (!NewBuffer)
867 {
868 DPRINT("ExAllocatePool() failed\n");
869 Status = STATUS_INSUFFICIENT_RESOURCES;
870 goto cleanup;
871 }
872 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
873 if (ReturnBuffer.Buffer)
874 ExFreePool(ReturnBuffer.Buffer);
875 ReturnBuffer.Buffer = NewBuffer;
876 }
877 DPRINT("Adding symbolic link %wZ\n", &KeyName);
878 Status = RtlAppendUnicodeStringToString(&ReturnBuffer, &KeyName);
879 if (!NT_SUCCESS(Status))
880 {
881 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
882 goto cleanup;
883 }
884 NextReferenceString:
885 ExFreePool(ReferenceBi);
886 ReferenceBi = NULL;
887 ExFreePool(bip);
888 bip = NULL;
889 if (ReferenceKey != INVALID_HANDLE_VALUE)
890 {
891 ZwClose(ReferenceKey);
892 ReferenceKey = INVALID_HANDLE_VALUE;
893 }
894 if (ControlKey != INVALID_HANDLE_VALUE)
895 {
896 ZwClose(ControlKey);
897 ControlKey = INVALID_HANDLE_VALUE;
898 }
899 }
900 if (FoundRightPDO)
901 {
902 /* No need to go further, as we already have found what we searched */
903 break;
904 }
905
906 ExFreePool(DeviceBi);
907 DeviceBi = NULL;
908 ZwClose(DeviceKey);
909 DeviceKey = INVALID_HANDLE_VALUE;
910 }
911
912 /* Add final NULL to ReturnBuffer */
913 if (ReturnBuffer.Length >= ReturnBuffer.MaximumLength)
914 {
915 PWSTR NewBuffer;
916 ReturnBuffer.MaximumLength += sizeof(WCHAR);
917 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength);
918 if (!NewBuffer)
919 {
920 DPRINT("ExAllocatePool() failed\n");
921 Status = STATUS_INSUFFICIENT_RESOURCES;
922 goto cleanup;
923 }
924 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length);
925 ExFreePool(ReturnBuffer.Buffer);
926 ReturnBuffer.Buffer = NewBuffer;
927 }
928 ReturnBuffer.Buffer[ReturnBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL;
929 *SymbolicLinkList = ReturnBuffer.Buffer;
930 Status = STATUS_SUCCESS;
931
932 cleanup:
933 if (!NT_SUCCESS(Status) && ReturnBuffer.Buffer)
934 ExFreePool(ReturnBuffer.Buffer);
935 if (InterfaceKey != INVALID_HANDLE_VALUE)
936 ZwClose(InterfaceKey);
937 if (DeviceKey != INVALID_HANDLE_VALUE)
938 ZwClose(DeviceKey);
939 if (ReferenceKey != INVALID_HANDLE_VALUE)
940 ZwClose(ReferenceKey);
941 if (ControlKey != INVALID_HANDLE_VALUE)
942 ZwClose(ControlKey);
943 if (DeviceBi)
944 ExFreePool(DeviceBi);
945 if (ReferenceBi)
946 ExFreePool(ReferenceBi);
947 if (bip)
948 ExFreePool(bip);
949 return Status;
950 }
951
952 /*++
953 * @name IoRegisterDeviceInterface
954 * @implemented
955 *
956 * Registers a device interface class, if it has not been previously registered,
957 * and creates a new instance of the interface class, which a driver can
958 * subsequently enable for use by applications or other system components.
959 * Documented in WDK.
960 *
961 * @param PhysicalDeviceObject
962 * Points to an optional PDO that narrows the search to only the
963 * device interfaces of the device represented by the PDO
964 *
965 * @param InterfaceClassGuid
966 * Points to a class GUID specifying the device interface class
967 *
968 * @param ReferenceString
969 * Optional parameter, pointing to a unicode string. For a full
970 * description of this rather rarely used param (usually drivers
971 * pass NULL here) see WDK
972 *
973 * @param SymbolicLinkName
974 * Pointer to the resulting unicode string
975 *
976 * @return Usual NTSTATUS
977 *
978 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
979 * system thread
980 *
981 *--*/
982 NTSTATUS
983 NTAPI
984 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject,
985 IN CONST GUID *InterfaceClassGuid,
986 IN PUNICODE_STRING ReferenceString OPTIONAL,
987 OUT PUNICODE_STRING SymbolicLinkName)
988 {
989 PUNICODE_STRING InstancePath;
990 UNICODE_STRING GuidString;
991 UNICODE_STRING SubKeyName;
992 UNICODE_STRING InterfaceKeyName;
993 UNICODE_STRING BaseKeyName;
994 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))];
995 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer;
996 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
997 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
998 HANDLE ClassKey;
999 HANDLE InterfaceKey;
1000 HANDLE SubKey;
1001 ULONG StartIndex;
1002 OBJECT_ATTRIBUTES ObjectAttributes;
1003 ULONG i;
1004 NTSTATUS Status;
1005 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension;
1006
1007 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
1008
1009 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
1010 PhysicalDeviceObject, ReferenceString);
1011
1012 /* Parameters must pass three border of checks */
1013 DeviceObjectExtension = (PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension;
1014
1015 /* 1st level: Presence of a Device Node */
1016 if (DeviceObjectExtension->DeviceNode == NULL)
1017 {
1018 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject);
1019 return STATUS_INVALID_DEVICE_REQUEST;
1020 }
1021
1022 /* 2nd level: Presence of an non-zero length InstancePath */
1023 if (DeviceObjectExtension->DeviceNode->InstancePath.Length == 0)
1024 {
1025 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject);
1026 return STATUS_INVALID_DEVICE_REQUEST;
1027 }
1028
1029 /* 3rd level: Optional, based on WDK documentation */
1030 if (ReferenceString != NULL)
1031 {
1032 /* Reference string must not contain path-separator symbols */
1033 for (i = 0; i < ReferenceString->Length / sizeof(WCHAR); i++)
1034 {
1035 if ((ReferenceString->Buffer[i] == '\\') ||
1036 (ReferenceString->Buffer[i] == '/'))
1037 return STATUS_INVALID_DEVICE_REQUEST;
1038 }
1039 }
1040
1041 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
1042 if (!NT_SUCCESS(Status))
1043 {
1044 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
1045 return Status;
1046 }
1047
1048 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
1049 Status = ObQueryNameString(
1050 PhysicalDeviceObject,
1051 PdoNameInfo,
1052 sizeof(PdoNameInfoBuffer),
1053 &i);
1054 if (!NT_SUCCESS(Status))
1055 {
1056 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status);
1057 return Status;
1058 }
1059 ASSERT(PdoNameInfo->Name.Length);
1060
1061 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1062 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode);
1063 InstancePath = &((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode->InstancePath;
1064 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
1065 BaseKeyName.MaximumLength = BaseKeyName.Length
1066 + GuidString.Length;
1067 BaseKeyName.Buffer = ExAllocatePool(
1068 PagedPool,
1069 BaseKeyName.MaximumLength);
1070 if (!BaseKeyName.Buffer)
1071 {
1072 DPRINT("ExAllocatePool() failed\n");
1073 return STATUS_INSUFFICIENT_RESOURCES;
1074 }
1075 wcscpy(BaseKeyName.Buffer, BaseKeyString);
1076 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
1077
1078 /* Create BaseKeyName key in registry */
1079 InitializeObjectAttributes(
1080 &ObjectAttributes,
1081 &BaseKeyName,
1082 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
1083 NULL, /* RootDirectory */
1084 NULL); /* SecurityDescriptor */
1085
1086 Status = ZwCreateKey(
1087 &ClassKey,
1088 KEY_WRITE,
1089 &ObjectAttributes,
1090 0, /* TileIndex */
1091 NULL, /* Class */
1092 REG_OPTION_VOLATILE,
1093 NULL); /* Disposition */
1094
1095 if (!NT_SUCCESS(Status))
1096 {
1097 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1098 ExFreePool(BaseKeyName.Buffer);
1099 return Status;
1100 }
1101
1102 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
1103 InterfaceKeyName.Length = 0;
1104 InterfaceKeyName.MaximumLength =
1105 4 * sizeof(WCHAR) + /* 4 = size of ##?# */
1106 InstancePath->Length +
1107 sizeof(WCHAR) + /* 1 = size of # */
1108 GuidString.Length;
1109 InterfaceKeyName.Buffer = ExAllocatePool(
1110 PagedPool,
1111 InterfaceKeyName.MaximumLength);
1112 if (!InterfaceKeyName.Buffer)
1113 {
1114 DPRINT("ExAllocatePool() failed\n");
1115 return STATUS_INSUFFICIENT_RESOURCES;
1116 }
1117
1118 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#");
1119 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR);
1120 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath);
1121 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1122 {
1123 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\')
1124 InterfaceKeyName.Buffer[StartIndex + i] = '#';
1125 }
1126 RtlAppendUnicodeToString(&InterfaceKeyName, L"#");
1127 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString);
1128
1129 /* Create the interface key in registry */
1130 InitializeObjectAttributes(
1131 &ObjectAttributes,
1132 &InterfaceKeyName,
1133 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
1134 ClassKey,
1135 NULL); /* SecurityDescriptor */
1136
1137 Status = ZwCreateKey(
1138 &InterfaceKey,
1139 KEY_WRITE,
1140 &ObjectAttributes,
1141 0, /* TileIndex */
1142 NULL, /* Class */
1143 REG_OPTION_VOLATILE,
1144 NULL); /* Disposition */
1145
1146 if (!NT_SUCCESS(Status))
1147 {
1148 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1149 ZwClose(ClassKey);
1150 ExFreePool(BaseKeyName.Buffer);
1151 return Status;
1152 }
1153
1154 /* Write DeviceInstance entry. Value is InstancePath */
1155 Status = ZwSetValueKey(
1156 InterfaceKey,
1157 &DeviceInstance,
1158 0, /* TileIndex */
1159 REG_SZ,
1160 InstancePath->Buffer,
1161 InstancePath->Length);
1162 if (!NT_SUCCESS(Status))
1163 {
1164 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1165 ZwClose(InterfaceKey);
1166 ZwClose(ClassKey);
1167 ExFreePool(InterfaceKeyName.Buffer);
1168 ExFreePool(BaseKeyName.Buffer);
1169 return Status;
1170 }
1171
1172 /* Create subkey. Name is #ReferenceString */
1173 SubKeyName.Length = 0;
1174 SubKeyName.MaximumLength = sizeof(WCHAR);
1175 if (ReferenceString && ReferenceString->Length)
1176 SubKeyName.MaximumLength += ReferenceString->Length;
1177 SubKeyName.Buffer = ExAllocatePool(
1178 PagedPool,
1179 SubKeyName.MaximumLength);
1180 if (!SubKeyName.Buffer)
1181 {
1182 DPRINT("ExAllocatePool() failed\n");
1183 ZwClose(InterfaceKey);
1184 ZwClose(ClassKey);
1185 ExFreePool(InterfaceKeyName.Buffer);
1186 ExFreePool(BaseKeyName.Buffer);
1187 return STATUS_INSUFFICIENT_RESOURCES;
1188 }
1189 RtlAppendUnicodeToString(&SubKeyName, L"#");
1190 if (ReferenceString && ReferenceString->Length)
1191 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
1192
1193 /* Create SubKeyName key in registry */
1194 InitializeObjectAttributes(
1195 &ObjectAttributes,
1196 &SubKeyName,
1197 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1198 InterfaceKey, /* RootDirectory */
1199 NULL); /* SecurityDescriptor */
1200
1201 Status = ZwCreateKey(
1202 &SubKey,
1203 KEY_WRITE,
1204 &ObjectAttributes,
1205 0, /* TileIndex */
1206 NULL, /* Class */
1207 REG_OPTION_VOLATILE,
1208 NULL); /* Disposition */
1209
1210 if (!NT_SUCCESS(Status))
1211 {
1212 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
1213 ZwClose(InterfaceKey);
1214 ZwClose(ClassKey);
1215 ExFreePool(InterfaceKeyName.Buffer);
1216 ExFreePool(BaseKeyName.Buffer);
1217 return Status;
1218 }
1219
1220 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1221 SymbolicLinkName->Length = 0;
1222 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
1223 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */
1224 + InstancePath->Length
1225 + sizeof(WCHAR) /* 1 = size of # */
1226 + GuidString.Length
1227 + sizeof(WCHAR); /* final NULL */
1228 if (ReferenceString && ReferenceString->Length)
1229 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
1230 SymbolicLinkName->Buffer = ExAllocatePool(
1231 PagedPool,
1232 SymbolicLinkName->MaximumLength);
1233 if (!SymbolicLinkName->Buffer)
1234 {
1235 DPRINT("ExAllocatePool() failed\n");
1236 ZwClose(SubKey);
1237 ZwClose(InterfaceKey);
1238 ZwClose(ClassKey);
1239 ExFreePool(InterfaceKeyName.Buffer);
1240 ExFreePool(SubKeyName.Buffer);
1241 ExFreePool(BaseKeyName.Buffer);
1242 return STATUS_INSUFFICIENT_RESOURCES;
1243 }
1244 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\");
1245 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
1246 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
1247 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
1248 {
1249 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
1250 SymbolicLinkName->Buffer[StartIndex + i] = '#';
1251 }
1252 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
1253 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
1254 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1255
1256 /* Create symbolic link */
1257 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name);
1258 Status = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name);
1259 if (!NT_SUCCESS(Status) && ReferenceString == NULL)
1260 {
1261 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
1262 ZwClose(SubKey);
1263 ZwClose(InterfaceKey);
1264 ZwClose(ClassKey);
1265 ExFreePool(SubKeyName.Buffer);
1266 ExFreePool(InterfaceKeyName.Buffer);
1267 ExFreePool(BaseKeyName.Buffer);
1268 ExFreePool(SymbolicLinkName->Buffer);
1269 return Status;
1270 }
1271
1272 if (ReferenceString && ReferenceString->Length)
1273 {
1274 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
1275 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
1276 }
1277 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0';
1278
1279 /* Write symbolic link name in registry */
1280 SymbolicLinkName->Buffer[1] = '\\';
1281 Status = ZwSetValueKey(
1282 SubKey,
1283 &SymbolicLink,
1284 0, /* TileIndex */
1285 REG_SZ,
1286 SymbolicLinkName->Buffer,
1287 SymbolicLinkName->Length);
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status);
1291 ExFreePool(SymbolicLinkName->Buffer);
1292 }
1293 else
1294 {
1295 SymbolicLinkName->Buffer[1] = '?';
1296 }
1297
1298 ZwClose(SubKey);
1299 ZwClose(InterfaceKey);
1300 ZwClose(ClassKey);
1301 ExFreePool(SubKeyName.Buffer);
1302 ExFreePool(InterfaceKeyName.Buffer);
1303 ExFreePool(BaseKeyName.Buffer);
1304
1305 return Status;
1306 }
1307
1308 /*++
1309 * @name IoSetDeviceInterfaceState
1310 * @implemented
1311 *
1312 * Enables or disables an instance of a previously registered device
1313 * interface class.
1314 * Documented in WDK.
1315 *
1316 * @param SymbolicLinkName
1317 * Pointer to the string identifying instance to enable or disable
1318 *
1319 * @param Enable
1320 * TRUE = enable, FALSE = disable
1321 *
1322 * @return Usual NTSTATUS
1323 *
1324 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1325 * system thread
1326 *
1327 *--*/
1328 NTSTATUS
1329 NTAPI
1330 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
1331 IN BOOLEAN Enable)
1332 {
1333 PDEVICE_OBJECT PhysicalDeviceObject;
1334 PFILE_OBJECT FileObject;
1335 UNICODE_STRING GuidString;
1336 UNICODE_STRING SymLink;
1337 PWCHAR StartPosition;
1338 PWCHAR EndPosition;
1339 NTSTATUS Status;
1340 LPCGUID EventGuid;
1341 HANDLE InstanceHandle, ControlHandle;
1342 UNICODE_STRING KeyName;
1343 OBJECT_ATTRIBUTES ObjectAttributes;
1344 ULONG LinkedValue;
1345
1346 if (SymbolicLinkName == NULL)
1347 return STATUS_INVALID_PARAMETER_1;
1348
1349 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1350
1351 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1352 /* Get GUID from SymbolicLinkName */
1353 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{');
1354 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}');
1355 if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
1356 {
1357 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1358 return STATUS_INVALID_PARAMETER_1;
1359 }
1360 GuidString.Buffer = StartPosition;
1361 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
1362
1363 SymLink.Buffer = SymbolicLinkName->Buffer;
1364 SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer);
1365 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable);
1366
1367 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
1368 KEY_CREATE_SUB_KEY,
1369 NULL,
1370 NULL,
1371 &InstanceHandle);
1372 if (!NT_SUCCESS(Status))
1373 return Status;
1374
1375 RtlInitUnicodeString(&KeyName, L"Control");
1376 InitializeObjectAttributes(&ObjectAttributes,
1377 &KeyName,
1378 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1379 InstanceHandle,
1380 NULL);
1381 Status = ZwCreateKey(&ControlHandle,
1382 KEY_SET_VALUE,
1383 &ObjectAttributes,
1384 0,
1385 NULL,
1386 REG_OPTION_VOLATILE,
1387 NULL);
1388 ZwClose(InstanceHandle);
1389 if (!NT_SUCCESS(Status))
1390 {
1391 DPRINT1("Failed to create the Control subkey\n");
1392 return Status;
1393 }
1394
1395 LinkedValue = (Enable ? 1 : 0);
1396
1397 RtlInitUnicodeString(&KeyName, L"Linked");
1398 Status = ZwSetValueKey(ControlHandle,
1399 &KeyName,
1400 0,
1401 REG_DWORD,
1402 &LinkedValue,
1403 sizeof(ULONG));
1404 ZwClose(ControlHandle);
1405 if (!NT_SUCCESS(Status))
1406 {
1407 DPRINT1("Failed to write the Linked value\n");
1408 return Status;
1409 }
1410
1411 /* Get pointer to the PDO */
1412 Status = IoGetDeviceObjectPointer(
1413 &SymLink,
1414 0, /* DesiredAccess */
1415 &FileObject,
1416 &PhysicalDeviceObject);
1417 if (!NT_SUCCESS(Status))
1418 {
1419 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status);
1420 return Status;
1421 }
1422
1423 EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL;
1424 IopNotifyPlugPlayNotification(
1425 PhysicalDeviceObject,
1426 EventCategoryDeviceInterfaceChange,
1427 EventGuid,
1428 &GuidString,
1429 (PVOID)SymbolicLinkName);
1430
1431 ObDereferenceObject(FileObject);
1432 DPRINT("Status %x\n", Status);
1433 return STATUS_SUCCESS;
1434 }
1435
1436 /* EOF */