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
];
54 PWCHAR Guid
, RefString
;
55 UNICODE_STRING DevParamU
= RTL_CONSTANT_STRING(L
"\\Device Parameters");
56 UNICODE_STRING PrefixU
= RTL_CONSTANT_STRING(L
"\\??\\");
57 UNICODE_STRING KeyPath
, KeyName
;
58 UNICODE_STRING MatchableGuid
;
59 UNICODE_STRING GuidString
;
60 HANDLE GuidKey
, hInterfaceKey
;
62 PKEY_BASIC_INFORMATION KeyInformation
;
63 ULONG KeyInformationLength
;
64 OBJECT_ATTRIBUTES ObjectAttributes
;
68 swprintf(StrBuff
, L
"##?#%s", &SymbolicLinkName
->Buffer
[PrefixU
.Length
/ sizeof(WCHAR
)]);
70 RefString
= wcsstr(StrBuff
, L
"\\");
76 RtlInitUnicodeString(&MatchableGuid
, StrBuff
);
78 Guid
= wcsstr(StrBuff
, L
"{");
80 return STATUS_OBJECT_NAME_NOT_FOUND
;
82 KeyPath
.Buffer
= PathBuff
;
84 KeyPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
86 GuidString
.Buffer
= Guid
;
87 GuidString
.Length
= GuidString
.MaximumLength
= 38 * sizeof(WCHAR
);
89 RtlAppendUnicodeToString(&KeyPath
, BaseKeyString
);
90 RtlAppendUnicodeStringToString(&KeyPath
, &GuidString
);
92 InitializeObjectAttributes(&ObjectAttributes
,
98 Status
= ZwOpenKey(&GuidKey
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
);
99 if (!NT_SUCCESS(Status
))
104 Status
= ZwEnumerateKey(GuidKey
,
110 if (Status
== STATUS_NO_MORE_ENTRIES
)
112 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
114 KeyInformationLength
= RequiredLength
;
115 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
119 return STATUS_INSUFFICIENT_RESOURCES
;
122 Status
= ZwEnumerateKey(GuidKey
,
126 KeyInformationLength
,
132 return STATUS_OBJECT_PATH_NOT_FOUND
;
136 if (!NT_SUCCESS(Status
))
142 KeyName
.Length
= KeyName
.MaximumLength
= KeyInformation
->NameLength
;
143 KeyName
.Buffer
= KeyInformation
->Name
;
145 if (!RtlEqualUnicodeString(&KeyName
, &MatchableGuid
, TRUE
))
147 ExFreePool(KeyInformation
);
152 RtlAppendUnicodeStringToString(&KeyPath
, &KeyName
);
153 RtlAppendUnicodeToString(&KeyPath
, L
"\\");
155 /* check for presence of a reference string */
158 /* append reference string */
160 RtlInitUnicodeString(&KeyName
, RefString
);
164 /* no reference string */
165 RtlInitUnicodeString(&KeyName
, L
"#");
167 RtlAppendUnicodeStringToString(&KeyPath
, &KeyName
);
169 /* initialize reference string attributes */
170 InitializeObjectAttributes(&ObjectAttributes
,
172 OBJ_CASE_INSENSITIVE
,
176 /* now open device interface key */
177 Status
= ZwOpenKey(&hInterfaceKey
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
);
179 if (NT_SUCCESS(Status
))
181 /* check if it provides a DeviceParameters key */
182 InitializeObjectAttributes(&ObjectAttributes
, &DevParamU
, OBJ_CASE_INSENSITIVE
, hInterfaceKey
, NULL
);
184 Status
= ZwCreateKey(DeviceInterfaceKey
, DesiredAccess
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
186 if (NT_SUCCESS(Status
))
188 /* DeviceParameters key present */
189 ZwClose(hInterfaceKey
);
193 /* fall back to device interface */
194 *DeviceInterfaceKey
= hInterfaceKey
;
195 Status
= STATUS_SUCCESS
;
199 /* close class key */
201 ExFreePool(KeyInformation
);
205 return STATUS_OBJECT_PATH_NOT_FOUND
;
209 * @name IoGetDeviceInterfaceAlias
212 * Returns the alias device interface of the specified device interface
213 * instance, if the alias exists.
216 * @param SymbolicLinkName
217 * Pointer to a string which identifies the device interface instance
219 * @param AliasInterfaceClassGuid
222 * @param AliasSymbolicLinkName
225 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
226 * otherwise (see WDK for details)
228 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
233 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
234 IN CONST GUID
*AliasInterfaceClassGuid
,
235 OUT PUNICODE_STRING AliasSymbolicLinkName
)
237 return STATUS_NOT_IMPLEMENTED
;
241 * @name IopOpenInterfaceKey
243 * Returns the alias device interface of the specified device interface
245 * @param InterfaceClassGuid
248 * @param DesiredAccess
251 * @param pInterfaceKey
254 * @return Usual NTSTATUS
260 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
261 IN ACCESS_MASK DesiredAccess
,
262 OUT HANDLE
*pInterfaceKey
)
264 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
265 UNICODE_STRING GuidString
;
266 UNICODE_STRING KeyName
;
267 OBJECT_ATTRIBUTES ObjectAttributes
;
268 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
271 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
273 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
274 if (!NT_SUCCESS(Status
))
276 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
281 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
282 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
285 DPRINT("ExAllocatePool() failed\n");
286 Status
= STATUS_INSUFFICIENT_RESOURCES
;
290 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
291 if (!NT_SUCCESS(Status
))
293 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
296 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
297 if (!NT_SUCCESS(Status
))
299 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
302 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
303 if (!NT_SUCCESS(Status
))
305 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
308 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
309 if (!NT_SUCCESS(Status
))
311 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
315 InitializeObjectAttributes(
318 OBJ_CASE_INSENSITIVE
,
325 if (!NT_SUCCESS(Status
))
327 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
331 *pInterfaceKey
= InterfaceKey
;
332 Status
= STATUS_SUCCESS
;
335 if (!NT_SUCCESS(Status
))
337 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
338 ZwClose(InterfaceKey
);
340 RtlFreeUnicodeString(&GuidString
);
341 RtlFreeUnicodeString(&KeyName
);
346 * @name IoGetDeviceInterfaces
349 * Returns a list of device interfaces of a particular device interface class.
352 * @param InterfaceClassGuid
353 * Points to a class GUID specifying the device interface class
355 * @param PhysicalDeviceObject
356 * Points to an optional PDO that narrows the search to only the
357 * device interfaces of the device represented by the PDO
360 * Specifies flags that modify the search for device interfaces. The
361 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
362 * returned symbolic links should contain also disabled device
363 * interfaces in addition to the enabled ones.
365 * @param SymbolicLinkList
366 * Points to a character pointer that is filled in on successful return
367 * with a list of unicode strings identifying the device interfaces
368 * that match the search criteria. The newly allocated buffer contains
369 * a list of symbolic link names. Each unicode string in the list is
370 * null-terminated; the end of the whole list is marked by an additional
371 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
372 * when it is no longer needed.
373 * If no device interfaces match the search criteria, this routine
374 * returns STATUS_SUCCESS and the string contains a single NULL
377 * @return Usual NTSTATUS
384 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
385 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
387 OUT PWSTR
*SymbolicLinkList
)
389 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
390 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
391 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
392 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
393 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
394 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
395 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
396 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
397 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
398 UNICODE_STRING KeyName
;
399 OBJECT_ATTRIBUTES ObjectAttributes
;
400 BOOLEAN FoundRightPDO
= FALSE
;
401 ULONG i
= 0, j
, Size
;
402 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
407 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
408 if (!NT_SUCCESS(Status
))
410 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
414 /* Enumerate subkeys (ie the different device objets) */
417 Status
= ZwEnumerateKey(
424 if (Status
== STATUS_NO_MORE_ENTRIES
)
428 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
430 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
434 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
437 DPRINT("ExAllocatePool() failed\n");
438 Status
= STATUS_INSUFFICIENT_RESOURCES
;
441 Status
= ZwEnumerateKey(
448 if (!NT_SUCCESS(Status
))
450 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
454 /* Open device key */
455 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
456 KeyName
.Buffer
= DeviceBi
->Name
;
457 InitializeObjectAttributes(
460 OBJ_CASE_INSENSITIVE
,
465 KEY_ENUMERATE_SUB_KEYS
,
467 if (!NT_SUCCESS(Status
))
469 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
473 if (PhysicalDeviceObject
)
475 /* Check if we are on the right physical device object,
476 * by reading the DeviceInstance string
478 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
479 //FoundRightPDO = TRUE;
480 Status
= STATUS_NOT_IMPLEMENTED
;
484 /* Enumerate subkeys (ie the different reference strings) */
488 Status
= ZwEnumerateKey(
495 if (Status
== STATUS_NO_MORE_ENTRIES
)
499 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
501 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
505 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
508 DPRINT("ExAllocatePool() failed\n");
509 Status
= STATUS_INSUFFICIENT_RESOURCES
;
512 Status
= ZwEnumerateKey(
519 if (!NT_SUCCESS(Status
))
521 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
525 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
526 KeyName
.Buffer
= ReferenceBi
->Name
;
527 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
529 /* Skip Control subkey */
530 goto NextReferenceString
;
533 /* Open reference key */
534 InitializeObjectAttributes(
537 OBJ_CASE_INSENSITIVE
,
544 if (!NT_SUCCESS(Status
))
546 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
550 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
552 /* We have to check if the interface is enabled, by
553 * reading the Linked value in the Control subkey
556 InitializeObjectAttributes(
559 OBJ_CASE_INSENSITIVE
,
566 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
568 /* That's OK. The key doesn't exist (yet) because
569 * the interface is not activated.
571 goto NextReferenceString
;
573 else if (!NT_SUCCESS(Status
))
575 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
579 /* FIXME: Read the Linked value
580 * If it doesn't exist => ERROR
581 * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
582 * If its value is 0, go to NextReferenceString
583 * At the moment, do as if it is active...
585 DPRINT1("Checking if device is enabled is not implemented yet!\n");
588 /* Read the SymbolicLink string and add it into SymbolicLinkList */
589 Status
= ZwQueryValueKey(
592 KeyValuePartialInformation
,
596 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
598 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
601 bip
= ExAllocatePool(PagedPool
, Size
);
604 DPRINT("ExAllocatePool() failed\n");
605 Status
= STATUS_INSUFFICIENT_RESOURCES
;
608 Status
= ZwQueryValueKey(
611 KeyValuePartialInformation
,
615 if (!NT_SUCCESS(Status
))
617 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
620 else if (bip
->Type
!= REG_SZ
)
622 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
623 Status
= STATUS_UNSUCCESSFUL
;
626 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
628 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
629 Status
= STATUS_UNSUCCESSFUL
;
632 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
633 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
634 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
636 /* Remove trailing NULL */
637 KeyName
.Length
-= sizeof(WCHAR
);
640 /* Add new symbolic link to symbolic link list */
641 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
644 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
645 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
648 DPRINT("ExAllocatePool() failed\n");
649 Status
= STATUS_INSUFFICIENT_RESOURCES
;
652 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
653 if (ReturnBuffer
.Buffer
)
654 ExFreePool(ReturnBuffer
.Buffer
);
655 ReturnBuffer
.Buffer
= NewBuffer
;
657 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
658 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
659 if (!NT_SUCCESS(Status
))
661 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
665 ExFreePool(ReferenceBi
);
669 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
671 ZwClose(ReferenceKey
);
672 ReferenceKey
= INVALID_HANDLE_VALUE
;
674 if (ControlKey
!= INVALID_HANDLE_VALUE
)
677 ControlKey
= INVALID_HANDLE_VALUE
;
682 /* No need to go further, as we already have found what we searched */
686 ExFreePool(DeviceBi
);
689 DeviceKey
= INVALID_HANDLE_VALUE
;
692 /* Add final NULL to ReturnBuffer */
693 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
696 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
697 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
700 DPRINT("ExAllocatePool() failed\n");
701 Status
= STATUS_INSUFFICIENT_RESOURCES
;
704 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
705 ExFreePool(ReturnBuffer
.Buffer
);
706 ReturnBuffer
.Buffer
= NewBuffer
;
708 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
709 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
710 Status
= STATUS_SUCCESS
;
713 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
714 ExFreePool(ReturnBuffer
.Buffer
);
715 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
716 ZwClose(InterfaceKey
);
717 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
719 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
720 ZwClose(ReferenceKey
);
721 if (ControlKey
!= INVALID_HANDLE_VALUE
)
724 ExFreePool(DeviceBi
);
726 ExFreePool(ReferenceBi
);
733 * @name IoRegisterDeviceInterface
736 * Registers a device interface class, if it has not been previously registered,
737 * and creates a new instance of the interface class, which a driver can
738 * subsequently enable for use by applications or other system components.
741 * @param PhysicalDeviceObject
742 * Points to an optional PDO that narrows the search to only the
743 * device interfaces of the device represented by the PDO
745 * @param InterfaceClassGuid
746 * Points to a class GUID specifying the device interface class
748 * @param ReferenceString
749 * Optional parameter, pointing to a unicode string. For a full
750 * description of this rather rarely used param (usually drivers
751 * pass NULL here) see WDK
753 * @param SymbolicLinkName
754 * Pointer to the resulting unicode string
756 * @return Usual NTSTATUS
758 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
764 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
765 IN CONST GUID
*InterfaceClassGuid
,
766 IN PUNICODE_STRING ReferenceString OPTIONAL
,
767 OUT PUNICODE_STRING SymbolicLinkName
)
769 PUNICODE_STRING InstancePath
;
770 UNICODE_STRING GuidString
;
771 UNICODE_STRING SubKeyName
;
772 UNICODE_STRING InterfaceKeyName
;
773 UNICODE_STRING BaseKeyName
;
774 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
775 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
776 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
777 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
782 OBJECT_ATTRIBUTES ObjectAttributes
;
785 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
787 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
789 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
790 PhysicalDeviceObject
, ReferenceString
);
792 /* Parameters must pass three border of checks */
793 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
795 /* 1st level: Presence of a Device Node */
796 if (DeviceObjectExtension
->DeviceNode
== NULL
)
798 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
799 return STATUS_INVALID_DEVICE_REQUEST
;
802 /* 2nd level: Presence of an non-zero length InstancePath */
803 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
805 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
806 return STATUS_INVALID_DEVICE_REQUEST
;
809 /* 3rd level: Optional, based on WDK documentation */
810 if (ReferenceString
!= NULL
)
812 /* Reference string must not contain path-separator symbols */
813 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
815 if ((ReferenceString
->Buffer
[i
] == '\\') ||
816 (ReferenceString
->Buffer
[i
] == '/'))
817 return STATUS_INVALID_DEVICE_REQUEST
;
821 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
822 if (!NT_SUCCESS(Status
))
824 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
828 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
829 Status
= ObQueryNameString(
830 PhysicalDeviceObject
,
832 sizeof(PdoNameInfoBuffer
),
834 if (!NT_SUCCESS(Status
))
836 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
839 ASSERT(PdoNameInfo
->Name
.Length
);
841 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
842 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
843 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
844 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
845 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
847 BaseKeyName
.Buffer
= ExAllocatePool(
849 BaseKeyName
.MaximumLength
);
850 if (!BaseKeyName
.Buffer
)
852 DPRINT("ExAllocatePool() failed\n");
853 return STATUS_INSUFFICIENT_RESOURCES
;
855 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
856 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
858 /* Create BaseKeyName key in registry */
859 InitializeObjectAttributes(
862 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
863 NULL
, /* RootDirectory */
864 NULL
); /* SecurityDescriptor */
866 Status
= ZwCreateKey(
873 NULL
); /* Disposition */
875 if (!NT_SUCCESS(Status
))
877 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
878 ExFreePool(BaseKeyName
.Buffer
);
882 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
883 InterfaceKeyName
.Length
= 0;
884 InterfaceKeyName
.MaximumLength
=
885 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
886 InstancePath
->Length
+
887 sizeof(WCHAR
) + /* 1 = size of # */
889 InterfaceKeyName
.Buffer
= ExAllocatePool(
891 InterfaceKeyName
.MaximumLength
);
892 if (!InterfaceKeyName
.Buffer
)
894 DPRINT("ExAllocatePool() failed\n");
895 return STATUS_INSUFFICIENT_RESOURCES
;
898 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
899 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
900 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
901 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
903 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
904 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
906 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
907 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
909 /* Create the interface key in registry */
910 InitializeObjectAttributes(
913 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
915 NULL
); /* SecurityDescriptor */
917 Status
= ZwCreateKey(
924 NULL
); /* Disposition */
926 if (!NT_SUCCESS(Status
))
928 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
930 ExFreePool(BaseKeyName
.Buffer
);
934 /* Write DeviceInstance entry. Value is InstancePath */
935 Status
= ZwSetValueKey(
940 InstancePath
->Buffer
,
941 InstancePath
->Length
);
942 if (!NT_SUCCESS(Status
))
944 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
945 ZwClose(InterfaceKey
);
947 ExFreePool(InterfaceKeyName
.Buffer
);
948 ExFreePool(BaseKeyName
.Buffer
);
952 /* Create subkey. Name is #ReferenceString */
953 SubKeyName
.Length
= 0;
954 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
955 if (ReferenceString
&& ReferenceString
->Length
)
956 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
957 SubKeyName
.Buffer
= ExAllocatePool(
959 SubKeyName
.MaximumLength
);
960 if (!SubKeyName
.Buffer
)
962 DPRINT("ExAllocatePool() failed\n");
963 ZwClose(InterfaceKey
);
965 ExFreePool(InterfaceKeyName
.Buffer
);
966 ExFreePool(BaseKeyName
.Buffer
);
967 return STATUS_INSUFFICIENT_RESOURCES
;
969 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
970 if (ReferenceString
&& ReferenceString
->Length
)
971 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
973 /* Create SubKeyName key in registry */
974 InitializeObjectAttributes(
977 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
978 InterfaceKey
, /* RootDirectory */
979 NULL
); /* SecurityDescriptor */
981 Status
= ZwCreateKey(
988 NULL
); /* Disposition */
990 if (!NT_SUCCESS(Status
))
992 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
993 ZwClose(InterfaceKey
);
995 ExFreePool(InterfaceKeyName
.Buffer
);
996 ExFreePool(BaseKeyName
.Buffer
);
1000 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1001 SymbolicLinkName
->Length
= 0;
1002 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
1003 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
1004 + InstancePath
->Length
1005 + sizeof(WCHAR
) /* 1 = size of # */
1007 + sizeof(WCHAR
); /* final NULL */
1008 if (ReferenceString
&& ReferenceString
->Length
)
1009 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
1010 SymbolicLinkName
->Buffer
= ExAllocatePool(
1012 SymbolicLinkName
->MaximumLength
);
1013 if (!SymbolicLinkName
->Buffer
)
1015 DPRINT("ExAllocatePool() failed\n");
1017 ZwClose(InterfaceKey
);
1019 ExFreePool(InterfaceKeyName
.Buffer
);
1020 ExFreePool(SubKeyName
.Buffer
);
1021 ExFreePool(BaseKeyName
.Buffer
);
1022 return STATUS_INSUFFICIENT_RESOURCES
;
1024 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
1025 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
1026 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
1027 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
1029 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
1030 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
1032 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
1033 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
1034 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1036 /* Create symbolic link */
1037 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
1038 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
1039 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
1041 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
1043 ZwClose(InterfaceKey
);
1045 ExFreePool(SubKeyName
.Buffer
);
1046 ExFreePool(InterfaceKeyName
.Buffer
);
1047 ExFreePool(BaseKeyName
.Buffer
);
1048 ExFreePool(SymbolicLinkName
->Buffer
);
1052 if (ReferenceString
&& ReferenceString
->Length
)
1054 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
1055 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
1057 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
1059 /* Write symbolic link name in registry */
1060 SymbolicLinkName
->Buffer
[1] = '\\';
1061 Status
= ZwSetValueKey(
1066 SymbolicLinkName
->Buffer
,
1067 SymbolicLinkName
->Length
);
1068 if (!NT_SUCCESS(Status
))
1070 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
1071 ExFreePool(SymbolicLinkName
->Buffer
);
1075 SymbolicLinkName
->Buffer
[1] = '?';
1079 ZwClose(InterfaceKey
);
1081 ExFreePool(SubKeyName
.Buffer
);
1082 ExFreePool(InterfaceKeyName
.Buffer
);
1083 ExFreePool(BaseKeyName
.Buffer
);
1089 * @name IoSetDeviceInterfaceState
1092 * Enables or disables an instance of a previously registered device
1094 * Documented in WDK.
1096 * @param SymbolicLinkName
1097 * Pointer to the string identifying instance to enable or disable
1100 * TRUE = enable, FALSE = disable
1102 * @return Usual NTSTATUS
1104 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
1110 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
1113 PDEVICE_OBJECT PhysicalDeviceObject
;
1114 PFILE_OBJECT FileObject
;
1115 UNICODE_STRING GuidString
;
1116 UNICODE_STRING SymLink
;
1117 PWCHAR StartPosition
;
1123 if (SymbolicLinkName
== NULL
)
1124 return STATUS_INVALID_PARAMETER_1
;
1126 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1128 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
1129 /* Get GUID from SymbolicLinkName */
1130 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
1131 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
1132 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
1134 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
1135 return STATUS_INVALID_PARAMETER_1
;
1137 GuidString
.Buffer
= StartPosition
;
1138 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
1140 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
1141 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
1142 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
1143 /* Get pointer to the PDO */
1144 Status
= IoGetDeviceObjectPointer(
1146 0, /* DesiredAccess */
1148 &PhysicalDeviceObject
);
1149 if (!NT_SUCCESS(Status
))
1151 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1155 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1156 IopNotifyPlugPlayNotification(
1157 PhysicalDeviceObject
,
1158 EventCategoryDeviceInterfaceChange
,
1161 (PVOID
)SymbolicLinkName
);
1163 ObDereferenceObject(FileObject
);
1164 DPRINT("Status %x\n", Status
);
1165 return STATUS_SUCCESS
;