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
7 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
8 * Matthew Brace (ismarc@austin.rr.com)
9 * Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES ******************************************************************/
19 /* FUNCTIONS *****************************************************************/
21 static PWCHAR BaseKeyString
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
24 * @name IoOpenDeviceInterfaceRegistryKey
27 * Provides a handle to the device's interface instance registry key.
30 * @param SymbolicLinkName
31 * Pointer to a string which identifies the device interface instance
33 * @param DesiredAccess
34 * Desired ACCESS_MASK used to access the key (like KEY_READ,
37 * @param DeviceInterfaceKey
38 * If a call has been succesfull, a handle to the registry key
39 * will be stored there
41 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
42 * otherwise (see WDK for details)
44 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
49 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName
,
50 IN ACCESS_MASK DesiredAccess
,
51 OUT PHANDLE DeviceInterfaceKey
)
53 WCHAR StrBuff
[MAX_PATH
], PathBuff
[MAX_PATH
];
55 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT L
"\\");
56 UNICODE_STRING DevParamU
= RTL_CONSTANT_STRING(L
"\\Device Parameters");
57 UNICODE_STRING PrefixU
= RTL_CONSTANT_STRING(L
"\\??\\");
58 UNICODE_STRING KeyPath
, KeyName
;
59 UNICODE_STRING MatchableGuid
;
60 HANDLE GuidKey
, ChildKey
;
62 PKEY_BASIC_INFORMATION KeyInformation
;
63 ULONG KeyInformationLength
;
64 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
65 ULONG KeyValueInformationLength
;
66 OBJECT_ATTRIBUTES ObjectAttributes
;
70 MatchableGuid
.Length
= 0;
71 MatchableGuid
.Length
+= swprintf(StrBuff
,
73 &SymbolicLinkName
->Buffer
[PrefixU
.Length
/ sizeof(WCHAR
)]);
74 StrBuff
[++MatchableGuid
.Length
] = UNICODE_NULL
;
76 MatchableGuid
.Buffer
= StrBuff
;
77 MatchableGuid
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
78 MatchableGuid
.Length
= (MatchableGuid
.Length
-1) * sizeof(WCHAR
);
80 Guid
= wcsstr(StrBuff
, L
"{");
82 return STATUS_OBJECT_NAME_NOT_FOUND
;
84 KeyPath
.Buffer
= PathBuff
;
86 KeyPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
88 RtlAppendUnicodeToString(&KeyPath
, BaseKeyString
);
89 RtlAppendUnicodeToString(&KeyPath
, Guid
);
91 InitializeObjectAttributes(&ObjectAttributes
,
97 Status
= ZwOpenKey(&GuidKey
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
);
98 if (!NT_SUCCESS(Status
))
103 Status
= ZwEnumerateKey(GuidKey
,
109 if (Status
== STATUS_NO_MORE_ENTRIES
)
111 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
113 KeyInformationLength
= RequiredLength
;
114 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
118 return STATUS_INSUFFICIENT_RESOURCES
;
121 Status
= ZwEnumerateKey(GuidKey
,
125 KeyInformationLength
,
131 return STATUS_OBJECT_PATH_NOT_FOUND
;
135 if (!NT_SUCCESS(Status
))
141 KeyName
.Length
= KeyName
.MaximumLength
= KeyInformation
->NameLength
;
142 KeyName
.Buffer
= KeyInformation
->Name
;
144 if (!RtlEqualUnicodeString(&KeyName
, &MatchableGuid
, TRUE
))
147 InitializeObjectAttributes(&ObjectAttributes
,
149 OBJ_CASE_INSENSITIVE
,
152 Status
= ZwOpenKey(&ChildKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
154 if (!NT_SUCCESS(Status
))
157 RtlInitUnicodeString(&KeyName
, L
"DeviceInstance");
158 Status
= ZwQueryValueKey(ChildKey
,
160 KeyValuePartialInformation
,
164 if (Status
== STATUS_BUFFER_TOO_SMALL
)
166 KeyValueInformationLength
= RequiredLength
;
167 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
168 if (!KeyValueInformation
)
174 Status
= ZwQueryValueKey(ChildKey
,
176 KeyValuePartialInformation
,
178 KeyValueInformationLength
,
184 return STATUS_OBJECT_PATH_NOT_FOUND
;
188 if (!NT_SUCCESS(Status
))
193 KeyName
.Length
= KeyName
.MaximumLength
= KeyValueInformation
->DataLength
;
194 KeyName
.Buffer
= (PWCHAR
)KeyValueInformation
->Data
;
196 RtlAppendUnicodeStringToString(&KeyPath
, &EnumU
);
197 RtlAppendUnicodeStringToString(&KeyPath
, &KeyName
);
198 RtlAppendUnicodeStringToString(&KeyPath
, &DevParamU
);
200 InitializeObjectAttributes(&ObjectAttributes
,
202 OBJ_CASE_INSENSITIVE
,
205 Status
= ZwCreateKey(DeviceInterfaceKey
,
210 REG_OPTION_NON_VOLATILE
,
215 return STATUS_OBJECT_PATH_NOT_FOUND
;
219 * @name IoGetDeviceInterfaceAlias
222 * Returns the alias device interface of the specified device interface
223 * instance, if the alias exists.
226 * @param SymbolicLinkName
227 * Pointer to a string which identifies the device interface instance
229 * @param AliasInterfaceClassGuid
232 * @param AliasSymbolicLinkName
235 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
236 * otherwise (see WDK for details)
238 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
243 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
244 IN CONST GUID
*AliasInterfaceClassGuid
,
245 OUT PUNICODE_STRING AliasSymbolicLinkName
)
247 return STATUS_NOT_IMPLEMENTED
;
251 * @name IopOpenInterfaceKey
253 * Returns the alias device interface of the specified device interface
255 * @param InterfaceClassGuid
258 * @param DesiredAccess
261 * @param pInterfaceKey
264 * @return Usual NTSTATUS
270 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
271 IN ACCESS_MASK DesiredAccess
,
272 OUT HANDLE
*pInterfaceKey
)
274 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
275 UNICODE_STRING GuidString
;
276 UNICODE_STRING KeyName
;
277 OBJECT_ATTRIBUTES ObjectAttributes
;
278 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
281 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
283 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
284 if (!NT_SUCCESS(Status
))
286 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
291 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
292 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
295 DPRINT("ExAllocatePool() failed\n");
296 Status
= STATUS_INSUFFICIENT_RESOURCES
;
300 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
301 if (!NT_SUCCESS(Status
))
303 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
306 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
307 if (!NT_SUCCESS(Status
))
309 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
312 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
313 if (!NT_SUCCESS(Status
))
315 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
318 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
319 if (!NT_SUCCESS(Status
))
321 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
325 InitializeObjectAttributes(
328 OBJ_CASE_INSENSITIVE
,
335 if (!NT_SUCCESS(Status
))
337 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
341 *pInterfaceKey
= InterfaceKey
;
342 Status
= STATUS_SUCCESS
;
345 if (!NT_SUCCESS(Status
))
347 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
348 ZwClose(InterfaceKey
);
350 RtlFreeUnicodeString(&GuidString
);
351 RtlFreeUnicodeString(&KeyName
);
356 * @name IoGetDeviceInterfaces
359 * Returns a list of device interfaces of a particular device interface class.
362 * @param InterfaceClassGuid
363 * Points to a class GUID specifying the device interface class
365 * @param PhysicalDeviceObject
366 * Points to an optional PDO that narrows the search to only the
367 * device interfaces of the device represented by the PDO
370 * Specifies flags that modify the search for device interfaces. The
371 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
372 * returned symbolic links should contain also disabled device
373 * interfaces in addition to the enabled ones.
375 * @param SymbolicLinkList
376 * Points to a character pointer that is filled in on successful return
377 * with a list of unicode strings identifying the device interfaces
378 * that match the search criteria. The newly allocated buffer contains
379 * a list of symbolic link names. Each unicode string in the list is
380 * null-terminated; the end of the whole list is marked by an additional
381 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
382 * when it is no longer needed.
383 * If no device interfaces match the search criteria, this routine
384 * returns STATUS_SUCCESS and the string contains a single NULL
387 * @return Usual NTSTATUS
394 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
395 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
397 OUT PWSTR
*SymbolicLinkList
)
399 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
400 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
401 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
402 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
403 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
404 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
405 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
406 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
407 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
408 UNICODE_STRING KeyName
;
409 OBJECT_ATTRIBUTES ObjectAttributes
;
410 BOOLEAN FoundRightPDO
= FALSE
;
411 ULONG i
= 0, j
, Size
;
412 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
417 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
418 if (!NT_SUCCESS(Status
))
420 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
424 /* Enumerate subkeys (ie the different device objets) */
427 Status
= ZwEnumerateKey(
434 if (Status
== STATUS_NO_MORE_ENTRIES
)
438 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
440 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
444 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
447 DPRINT("ExAllocatePool() failed\n");
448 Status
= STATUS_INSUFFICIENT_RESOURCES
;
451 Status
= ZwEnumerateKey(
458 if (!NT_SUCCESS(Status
))
460 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
464 /* Open device key */
465 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
466 KeyName
.Buffer
= DeviceBi
->Name
;
467 InitializeObjectAttributes(
470 OBJ_CASE_INSENSITIVE
,
475 KEY_ENUMERATE_SUB_KEYS
,
477 if (!NT_SUCCESS(Status
))
479 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
483 if (PhysicalDeviceObject
)
485 /* Check if we are on the right physical device object,
486 * by reading the DeviceInstance string
488 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
489 //FoundRightPDO = TRUE;
490 Status
= STATUS_NOT_IMPLEMENTED
;
494 /* Enumerate subkeys (ie the different reference strings) */
498 Status
= ZwEnumerateKey(
505 if (Status
== STATUS_NO_MORE_ENTRIES
)
509 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
511 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
515 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
518 DPRINT("ExAllocatePool() failed\n");
519 Status
= STATUS_INSUFFICIENT_RESOURCES
;
522 Status
= ZwEnumerateKey(
529 if (!NT_SUCCESS(Status
))
531 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
535 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
536 KeyName
.Buffer
= ReferenceBi
->Name
;
537 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
539 /* Skip Control subkey */
540 goto NextReferenceString
;
543 /* Open reference key */
544 InitializeObjectAttributes(
547 OBJ_CASE_INSENSITIVE
,
554 if (!NT_SUCCESS(Status
))
556 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
560 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
562 /* We have to check if the interface is enabled, by
563 * reading the Linked value in the Control subkey
566 InitializeObjectAttributes(
569 OBJ_CASE_INSENSITIVE
,
576 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
578 /* That's OK. The key doesn't exist (yet) because
579 * the interface is not activated.
581 goto NextReferenceString
;
583 else if (!NT_SUCCESS(Status
))
585 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
589 /* FIXME: Read the Linked value
590 * If it doesn't exist => ERROR
591 * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
592 * If its value is 0, go to NextReferenceString
593 * At the moment, do as if it is active...
595 DPRINT1("Checking if device is enabled is not implemented yet!\n");
598 /* Read the SymbolicLink string and add it into SymbolicLinkList */
599 Status
= ZwQueryValueKey(
602 KeyValuePartialInformation
,
606 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
608 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
611 bip
= ExAllocatePool(PagedPool
, Size
);
614 DPRINT("ExAllocatePool() failed\n");
615 Status
= STATUS_INSUFFICIENT_RESOURCES
;
618 Status
= ZwQueryValueKey(
621 KeyValuePartialInformation
,
625 if (!NT_SUCCESS(Status
))
627 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
630 else if (bip
->Type
!= REG_SZ
)
632 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
633 Status
= STATUS_UNSUCCESSFUL
;
636 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
638 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
639 Status
= STATUS_UNSUCCESSFUL
;
642 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
643 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
644 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
646 /* Remove trailing NULL */
647 KeyName
.Length
-= sizeof(WCHAR
);
650 /* Add new symbolic link to symbolic link list */
651 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
654 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
655 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
658 DPRINT("ExAllocatePool() failed\n");
659 Status
= STATUS_INSUFFICIENT_RESOURCES
;
662 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
663 if (ReturnBuffer
.Buffer
)
664 ExFreePool(ReturnBuffer
.Buffer
);
665 ReturnBuffer
.Buffer
= NewBuffer
;
667 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
668 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
669 if (!NT_SUCCESS(Status
))
671 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
674 /* RtlAppendUnicodeStringToString added a NULL at the end of the
675 * destination string, but didn't increase the Length field.
678 ReturnBuffer
.Length
+= sizeof(WCHAR
);
681 ExFreePool(ReferenceBi
);
685 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
687 ZwClose(ReferenceKey
);
688 ReferenceKey
= INVALID_HANDLE_VALUE
;
690 if (ControlKey
!= INVALID_HANDLE_VALUE
)
693 ControlKey
= INVALID_HANDLE_VALUE
;
698 /* No need to go further, as we already have found what we searched */
702 ExFreePool(DeviceBi
);
705 DeviceKey
= INVALID_HANDLE_VALUE
;
708 /* Add final NULL to ReturnBuffer */
709 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
712 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
713 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
716 DPRINT("ExAllocatePool() failed\n");
717 Status
= STATUS_INSUFFICIENT_RESOURCES
;
720 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
721 ExFreePool(ReturnBuffer
.Buffer
);
722 ReturnBuffer
.Buffer
= NewBuffer
;
724 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
725 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
726 Status
= STATUS_SUCCESS
;
729 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
730 ExFreePool(ReturnBuffer
.Buffer
);
731 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
732 ZwClose(InterfaceKey
);
733 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
735 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
736 ZwClose(ReferenceKey
);
737 if (ControlKey
!= INVALID_HANDLE_VALUE
)
740 ExFreePool(DeviceBi
);
742 ExFreePool(ReferenceBi
);
749 * @name IoRegisterDeviceInterface
752 * Registers a device interface class, if it has not been previously registered,
753 * and creates a new instance of the interface class, which a driver can
754 * subsequently enable for use by applications or other system components.
757 * @param PhysicalDeviceObject
758 * Points to an optional PDO that narrows the search to only the
759 * device interfaces of the device represented by the PDO
761 * @param InterfaceClassGuid
762 * Points to a class GUID specifying the device interface class
764 * @param ReferenceString
765 * Optional parameter, pointing to a unicode string. For a full
766 * description of this rather rarely used param (usually drivers
767 * pass NULL here) see WDK
769 * @param SymbolicLinkName
770 * Pointer to the resulting unicode string
772 * @return Usual NTSTATUS
774 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
780 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
781 IN CONST GUID
*InterfaceClassGuid
,
782 IN PUNICODE_STRING ReferenceString OPTIONAL
,
783 OUT PUNICODE_STRING SymbolicLinkName
)
785 PUNICODE_STRING InstancePath
;
786 UNICODE_STRING GuidString
;
787 UNICODE_STRING SubKeyName
;
788 UNICODE_STRING InterfaceKeyName
;
789 UNICODE_STRING BaseKeyName
;
790 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
791 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
792 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
793 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
798 OBJECT_ATTRIBUTES ObjectAttributes
;
801 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
803 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
805 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
806 PhysicalDeviceObject
, ReferenceString
);
808 /* Parameters must pass three border of checks */
809 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
811 /* 1st level: Presence of a Device Node */
812 if (DeviceObjectExtension
->DeviceNode
== NULL
)
814 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
815 return STATUS_INVALID_DEVICE_REQUEST
;
818 /* 2nd level: Presence of an non-zero length InstancePath */
819 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
821 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
822 return STATUS_INVALID_DEVICE_REQUEST
;
825 /* 3rd level: Optional, based on WDK documentation */
826 if (ReferenceString
!= NULL
)
828 /* Reference string must not contain path-separator symbols */
829 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
831 if ((ReferenceString
->Buffer
[i
] == '\\') ||
832 (ReferenceString
->Buffer
[i
] == '/'))
833 return STATUS_INVALID_DEVICE_REQUEST
;
837 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
838 if (!NT_SUCCESS(Status
))
840 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
844 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
845 Status
= ObQueryNameString(
846 PhysicalDeviceObject
,
848 sizeof(PdoNameInfoBuffer
),
850 if (!NT_SUCCESS(Status
))
852 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
855 ASSERT(PdoNameInfo
->Name
.Length
);
857 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
858 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
859 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
860 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
861 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
863 BaseKeyName
.Buffer
= ExAllocatePool(
865 BaseKeyName
.MaximumLength
);
866 if (!BaseKeyName
.Buffer
)
868 DPRINT("ExAllocatePool() failed\n");
869 return STATUS_INSUFFICIENT_RESOURCES
;
871 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
872 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
874 /* Create BaseKeyName key in registry */
875 InitializeObjectAttributes(
878 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
879 NULL
, /* RootDirectory */
880 NULL
); /* SecurityDescriptor */
882 Status
= ZwCreateKey(
889 NULL
); /* Disposition */
891 if (!NT_SUCCESS(Status
))
893 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
894 ExFreePool(BaseKeyName
.Buffer
);
898 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
899 InterfaceKeyName
.Length
= 0;
900 InterfaceKeyName
.MaximumLength
=
901 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
902 InstancePath
->Length
+
903 sizeof(WCHAR
) + /* 1 = size of # */
905 InterfaceKeyName
.Buffer
= ExAllocatePool(
907 InterfaceKeyName
.MaximumLength
);
908 if (!InterfaceKeyName
.Buffer
)
910 DPRINT("ExAllocatePool() failed\n");
911 return STATUS_INSUFFICIENT_RESOURCES
;
914 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
915 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
916 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
917 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
919 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
920 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
922 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
923 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
925 /* Create the interface key in registry */
926 InitializeObjectAttributes(
929 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
931 NULL
); /* SecurityDescriptor */
933 Status
= ZwCreateKey(
940 NULL
); /* Disposition */
942 if (!NT_SUCCESS(Status
))
944 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
946 ExFreePool(BaseKeyName
.Buffer
);
950 /* Write DeviceInstance entry. Value is InstancePath */
951 Status
= ZwSetValueKey(
956 InstancePath
->Buffer
,
957 InstancePath
->Length
);
958 if (!NT_SUCCESS(Status
))
960 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
961 ZwClose(InterfaceKey
);
963 ExFreePool(InterfaceKeyName
.Buffer
);
964 ExFreePool(BaseKeyName
.Buffer
);
968 /* Create subkey. Name is #ReferenceString */
969 SubKeyName
.Length
= 0;
970 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
971 if (ReferenceString
&& ReferenceString
->Length
)
972 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
973 SubKeyName
.Buffer
= ExAllocatePool(
975 SubKeyName
.MaximumLength
);
976 if (!SubKeyName
.Buffer
)
978 DPRINT("ExAllocatePool() failed\n");
979 ZwClose(InterfaceKey
);
981 ExFreePool(InterfaceKeyName
.Buffer
);
982 ExFreePool(BaseKeyName
.Buffer
);
983 return STATUS_INSUFFICIENT_RESOURCES
;
985 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
986 if (ReferenceString
&& ReferenceString
->Length
)
987 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
989 /* Create SubKeyName key in registry */
990 InitializeObjectAttributes(
993 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
994 InterfaceKey
, /* RootDirectory */
995 NULL
); /* SecurityDescriptor */
997 Status
= ZwCreateKey(
1003 REG_OPTION_VOLATILE
,
1004 NULL
); /* Disposition */
1006 if (!NT_SUCCESS(Status
))
1008 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
1009 ZwClose(InterfaceKey
);
1011 ExFreePool(InterfaceKeyName
.Buffer
);
1012 ExFreePool(BaseKeyName
.Buffer
);
1016 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1017 SymbolicLinkName
->Length
= 0;
1018 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
1019 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
1020 + InstancePath
->Length
1021 + sizeof(WCHAR
) /* 1 = size of # */
1023 + sizeof(WCHAR
); /* final NULL */
1024 if (ReferenceString
&& ReferenceString
->Length
)
1025 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
1026 SymbolicLinkName
->Buffer
= ExAllocatePool(
1028 SymbolicLinkName
->MaximumLength
);
1029 if (!SymbolicLinkName
->Buffer
)
1031 DPRINT("ExAllocatePool() failed\n");
1033 ZwClose(InterfaceKey
);
1035 ExFreePool(InterfaceKeyName
.Buffer
);
1036 ExFreePool(SubKeyName
.Buffer
);
1037 ExFreePool(BaseKeyName
.Buffer
);
1038 return STATUS_INSUFFICIENT_RESOURCES
;
1040 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
1041 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
1042 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
1043 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1045 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
1046 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
1048 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
1049 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
1050 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1052 /* Create symbolic link */
1053 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
1054 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
1055 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
1057 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
1059 ZwClose(InterfaceKey
);
1061 ExFreePool(SubKeyName
.Buffer
);
1062 ExFreePool(InterfaceKeyName
.Buffer
);
1063 ExFreePool(BaseKeyName
.Buffer
);
1064 ExFreePool(SymbolicLinkName
->Buffer
);
1068 if (ReferenceString
&& ReferenceString
->Length
)
1070 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
1071 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
1073 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1075 /* Write symbolic link name in registry */
1076 SymbolicLinkName
->Buffer
[1] = '\\';
1077 Status
= ZwSetValueKey(
1082 SymbolicLinkName
->Buffer
,
1083 SymbolicLinkName
->Length
);
1084 if (!NT_SUCCESS(Status
))
1086 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1087 ExFreePool(SymbolicLinkName
->Buffer
);
1091 SymbolicLinkName
->Buffer
[1] = '?';
1095 ZwClose(InterfaceKey
);
1097 ExFreePool(SubKeyName
.Buffer
);
1098 ExFreePool(InterfaceKeyName
.Buffer
);
1099 ExFreePool(BaseKeyName
.Buffer
);
1105 * @name IoSetDeviceInterfaceState
1108 * Enables or disables an instance of a previously registered device
1110 * Documented in WDK.
1112 * @param SymbolicLinkName
1113 * Pointer to the string identifying instance to enable or disable
1116 * TRUE = enable, FALSE = disable
1118 * @return Usual NTSTATUS
1120 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1126 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
1129 PDEVICE_OBJECT PhysicalDeviceObject
;
1130 PFILE_OBJECT FileObject
;
1131 UNICODE_STRING GuidString
;
1132 UNICODE_STRING SymLink
;
1133 PWCHAR StartPosition
;
1139 if (SymbolicLinkName
== NULL
)
1140 return STATUS_INVALID_PARAMETER_1
;
1142 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1144 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1145 /* Get GUID from SymbolicLinkName */
1146 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
1147 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
1148 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
1150 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1151 return STATUS_INVALID_PARAMETER_1
;
1153 GuidString
.Buffer
= StartPosition
;
1154 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
1156 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
1157 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
1158 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1159 /* Get pointer to the PDO */
1160 Status
= IoGetDeviceObjectPointer(
1162 0, /* DesiredAccess */
1164 &PhysicalDeviceObject
);
1165 if (!NT_SUCCESS(Status
))
1167 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1171 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1172 IopNotifyPlugPlayNotification(
1173 PhysicalDeviceObject
,
1174 EventCategoryDeviceInterfaceChange
,
1177 (PVOID
)SymbolicLinkName
);
1179 ObDereferenceObject(FileObject
);
1180 DPRINT("Status %x\n", Status
);
1181 return STATUS_SUCCESS
;