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 return STATUS_NOT_IMPLEMENTED
;
57 * @name IoGetDeviceInterfaceAlias
60 * Returns the alias device interface of the specified device interface
61 * instance, if the alias exists.
64 * @param SymbolicLinkName
65 * Pointer to a string which identifies the device interface instance
67 * @param AliasInterfaceClassGuid
70 * @param AliasSymbolicLinkName
73 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS
74 * otherwise (see WDK for details)
76 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread
81 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName
,
82 IN CONST GUID
*AliasInterfaceClassGuid
,
83 OUT PUNICODE_STRING AliasSymbolicLinkName
)
85 return STATUS_NOT_IMPLEMENTED
;
89 * @name IopOpenInterfaceKey
91 * Returns the alias device interface of the specified device interface
93 * @param InterfaceClassGuid
96 * @param DesiredAccess
99 * @param pInterfaceKey
102 * @return Usual NTSTATUS
108 IopOpenInterfaceKey(IN CONST GUID
*InterfaceClassGuid
,
109 IN ACCESS_MASK DesiredAccess
,
110 OUT HANDLE
*pInterfaceKey
)
112 UNICODE_STRING LocalMachine
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\");
113 UNICODE_STRING GuidString
;
114 UNICODE_STRING KeyName
;
115 OBJECT_ATTRIBUTES ObjectAttributes
;
116 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
119 GuidString
.Buffer
= KeyName
.Buffer
= NULL
;
121 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
122 if (!NT_SUCCESS(Status
))
124 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
129 KeyName
.MaximumLength
= LocalMachine
.Length
+ (wcslen(REGSTR_PATH_DEVICE_CLASSES
) + 1) * sizeof(WCHAR
) + GuidString
.Length
;
130 KeyName
.Buffer
= ExAllocatePool(PagedPool
, KeyName
.MaximumLength
);
133 DPRINT("ExAllocatePool() failed\n");
134 Status
= STATUS_INSUFFICIENT_RESOURCES
;
138 Status
= RtlAppendUnicodeStringToString(&KeyName
, &LocalMachine
);
139 if (!NT_SUCCESS(Status
))
141 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
144 Status
= RtlAppendUnicodeToString(&KeyName
, REGSTR_PATH_DEVICE_CLASSES
);
145 if (!NT_SUCCESS(Status
))
147 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
150 Status
= RtlAppendUnicodeToString(&KeyName
, L
"\\");
151 if (!NT_SUCCESS(Status
))
153 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
156 Status
= RtlAppendUnicodeStringToString(&KeyName
, &GuidString
);
157 if (!NT_SUCCESS(Status
))
159 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
163 InitializeObjectAttributes(
166 OBJ_CASE_INSENSITIVE
,
173 if (!NT_SUCCESS(Status
))
175 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
179 *pInterfaceKey
= InterfaceKey
;
180 Status
= STATUS_SUCCESS
;
183 if (!NT_SUCCESS(Status
))
185 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
186 ZwClose(InterfaceKey
);
188 RtlFreeUnicodeString(&GuidString
);
189 RtlFreeUnicodeString(&KeyName
);
194 * @name IoGetDeviceInterfaces
197 * Returns a list of device interfaces of a particular device interface class.
200 * @param InterfaceClassGuid
201 * Points to a class GUID specifying the device interface class
203 * @param PhysicalDeviceObject
204 * Points to an optional PDO that narrows the search to only the
205 * device interfaces of the device represented by the PDO
208 * Specifies flags that modify the search for device interfaces. The
209 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
210 * returned symbolic links should contain also disabled device
211 * interfaces in addition to the enabled ones.
213 * @param SymbolicLinkList
214 * Points to a character pointer that is filled in on successful return
215 * with a list of unicode strings identifying the device interfaces
216 * that match the search criteria. The newly allocated buffer contains
217 * a list of symbolic link names. Each unicode string in the list is
218 * null-terminated; the end of the whole list is marked by an additional
219 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
220 * when it is no longer needed.
221 * If no device interfaces match the search criteria, this routine
222 * returns STATUS_SUCCESS and the string contains a single NULL
225 * @return Usual NTSTATUS
232 IoGetDeviceInterfaces(IN CONST GUID
*InterfaceClassGuid
,
233 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
235 OUT PWSTR
*SymbolicLinkList
)
237 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
238 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
239 HANDLE InterfaceKey
= INVALID_HANDLE_VALUE
;
240 HANDLE DeviceKey
= INVALID_HANDLE_VALUE
;
241 HANDLE ReferenceKey
= INVALID_HANDLE_VALUE
;
242 HANDLE ControlKey
= INVALID_HANDLE_VALUE
;
243 PKEY_BASIC_INFORMATION DeviceBi
= NULL
;
244 PKEY_BASIC_INFORMATION ReferenceBi
= NULL
;
245 PKEY_VALUE_PARTIAL_INFORMATION bip
= NULL
;
246 UNICODE_STRING KeyName
;
247 OBJECT_ATTRIBUTES ObjectAttributes
;
248 BOOLEAN FoundRightPDO
= FALSE
;
249 ULONG i
= 0, j
, Size
;
250 UNICODE_STRING ReturnBuffer
= { 0, 0, NULL
};
255 Status
= IopOpenInterfaceKey(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, &InterfaceKey
);
256 if (!NT_SUCCESS(Status
))
258 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status
);
262 /* Enumerate subkeys (ie the different device objets) */
265 Status
= ZwEnumerateKey(
272 if (Status
== STATUS_NO_MORE_ENTRIES
)
276 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
278 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
282 DeviceBi
= ExAllocatePool(PagedPool
, Size
);
285 DPRINT("ExAllocatePool() failed\n");
286 Status
= STATUS_INSUFFICIENT_RESOURCES
;
289 Status
= ZwEnumerateKey(
296 if (!NT_SUCCESS(Status
))
298 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
302 /* Open device key */
303 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)DeviceBi
->NameLength
;
304 KeyName
.Buffer
= DeviceBi
->Name
;
305 InitializeObjectAttributes(
308 OBJ_CASE_INSENSITIVE
,
313 KEY_ENUMERATE_SUB_KEYS
,
315 if (!NT_SUCCESS(Status
))
317 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
321 if (PhysicalDeviceObject
)
323 /* Check if we are on the right physical device object,
324 * by reading the DeviceInstance string
326 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n");
327 //FoundRightPDO = TRUE;
328 Status
= STATUS_NOT_IMPLEMENTED
;
332 /* Enumerate subkeys (ie the different reference strings) */
336 Status
= ZwEnumerateKey(
343 if (Status
== STATUS_NO_MORE_ENTRIES
)
347 else if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
349 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
353 ReferenceBi
= ExAllocatePool(PagedPool
, Size
);
356 DPRINT("ExAllocatePool() failed\n");
357 Status
= STATUS_INSUFFICIENT_RESOURCES
;
360 Status
= ZwEnumerateKey(
367 if (!NT_SUCCESS(Status
))
369 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
373 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)ReferenceBi
->NameLength
;
374 KeyName
.Buffer
= ReferenceBi
->Name
;
375 if (RtlEqualUnicodeString(&KeyName
, &Control
, TRUE
))
377 /* Skip Control subkey */
378 goto NextReferenceString
;
381 /* Open reference key */
382 InitializeObjectAttributes(
385 OBJ_CASE_INSENSITIVE
,
392 if (!NT_SUCCESS(Status
))
394 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
398 if (!(Flags
& DEVICE_INTERFACE_INCLUDE_NONACTIVE
))
400 /* We have to check if the interface is enabled, by
401 * reading the Linked value in the Control subkey
404 InitializeObjectAttributes(
407 OBJ_CASE_INSENSITIVE
,
414 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
416 /* That's OK. The key doesn't exist (yet) because
417 * the interface is not activated.
419 goto NextReferenceString
;
421 else if (!NT_SUCCESS(Status
))
423 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
427 /* FIXME: Read the Linked value
428 * If it doesn't exist => ERROR
429 * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
430 * If its value is 0, go to NextReferenceString
431 * At the moment, do as if it is active...
433 DPRINT1("Checking if device is enabled is not implemented yet!\n");
436 /* Read the SymbolicLink string and add it into SymbolicLinkList */
437 Status
= ZwQueryValueKey(
440 KeyValuePartialInformation
,
444 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
446 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
449 bip
= ExAllocatePool(PagedPool
, Size
);
452 DPRINT("ExAllocatePool() failed\n");
453 Status
= STATUS_INSUFFICIENT_RESOURCES
;
456 Status
= ZwQueryValueKey(
459 KeyValuePartialInformation
,
463 if (!NT_SUCCESS(Status
))
465 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
468 else if (bip
->Type
!= REG_SZ
)
470 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
471 Status
= STATUS_UNSUCCESSFUL
;
474 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
476 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
477 Status
= STATUS_UNSUCCESSFUL
;
480 KeyName
.Length
= KeyName
.MaximumLength
= (USHORT
)bip
->DataLength
- 4 * sizeof(WCHAR
);
481 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
482 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
484 /* Remove trailing NULL */
485 KeyName
.Length
-= sizeof(WCHAR
);
488 /* Add new symbolic link to symbolic link list */
489 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
492 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
493 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
496 DPRINT("ExAllocatePool() failed\n");
497 Status
= STATUS_INSUFFICIENT_RESOURCES
;
500 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
501 if (ReturnBuffer
.Buffer
)
502 ExFreePool(ReturnBuffer
.Buffer
);
503 ReturnBuffer
.Buffer
= NewBuffer
;
505 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
506 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
507 if (!NT_SUCCESS(Status
))
509 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
512 /* RtlAppendUnicodeStringToString added a NULL at the end of the
513 * destination string, but didn't increase the Length field.
516 ReturnBuffer
.Length
+= sizeof(WCHAR
);
519 ExFreePool(ReferenceBi
);
523 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
525 ZwClose(ReferenceKey
);
526 ReferenceKey
= INVALID_HANDLE_VALUE
;
528 if (ControlKey
!= INVALID_HANDLE_VALUE
)
531 ControlKey
= INVALID_HANDLE_VALUE
;
536 /* No need to go further, as we already have found what we searched */
540 ExFreePool(DeviceBi
);
543 DeviceKey
= INVALID_HANDLE_VALUE
;
546 /* Add final NULL to ReturnBuffer */
547 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
550 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
551 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
554 DPRINT("ExAllocatePool() failed\n");
555 Status
= STATUS_INSUFFICIENT_RESOURCES
;
558 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
559 ExFreePool(ReturnBuffer
.Buffer
);
560 ReturnBuffer
.Buffer
= NewBuffer
;
562 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
563 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
564 Status
= STATUS_SUCCESS
;
567 if (!NT_SUCCESS(Status
) && ReturnBuffer
.Buffer
)
568 ExFreePool(ReturnBuffer
.Buffer
);
569 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
570 ZwClose(InterfaceKey
);
571 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
573 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
574 ZwClose(ReferenceKey
);
575 if (ControlKey
!= INVALID_HANDLE_VALUE
)
578 ExFreePool(DeviceBi
);
580 ExFreePool(ReferenceBi
);
587 * @name IoRegisterDeviceInterface
590 * Registers a device interface class, if it has not been previously registered,
591 * and creates a new instance of the interface class, which a driver can
592 * subsequently enable for use by applications or other system components.
595 * @param PhysicalDeviceObject
596 * Points to an optional PDO that narrows the search to only the
597 * device interfaces of the device represented by the PDO
599 * @param InterfaceClassGuid
600 * Points to a class GUID specifying the device interface class
602 * @param ReferenceString
603 * Optional parameter, pointing to a unicode string. For a full
604 * description of this rather rarely used param (usually drivers
605 * pass NULL here) see WDK
607 * @param SymbolicLinkName
608 * Pointer to the resulting unicode string
610 * @return Usual NTSTATUS
612 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
618 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
619 IN CONST GUID
*InterfaceClassGuid
,
620 IN PUNICODE_STRING ReferenceString OPTIONAL
,
621 OUT PUNICODE_STRING SymbolicLinkName
)
623 PUNICODE_STRING InstancePath
;
624 UNICODE_STRING GuidString
;
625 UNICODE_STRING SubKeyName
;
626 UNICODE_STRING InterfaceKeyName
;
627 UNICODE_STRING BaseKeyName
;
628 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
629 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
630 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
631 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
636 OBJECT_ATTRIBUTES ObjectAttributes
;
639 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
641 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
643 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
644 PhysicalDeviceObject
, ReferenceString
);
646 /* Parameters must pass three border of checks */
647 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
649 /* 1st level: Presence of a Device Node */
650 if (DeviceObjectExtension
->DeviceNode
== NULL
)
652 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
653 return STATUS_INVALID_DEVICE_REQUEST
;
656 /* 2nd level: Presence of an non-zero length InstancePath */
657 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
659 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
660 return STATUS_INVALID_DEVICE_REQUEST
;
663 /* 3rd level: Optional, based on WDK documentation */
664 if (ReferenceString
!= NULL
)
666 /* Reference string must not contain path-separator symbols */
667 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
669 if ((ReferenceString
->Buffer
[i
] == '\\') ||
670 (ReferenceString
->Buffer
[i
] == '/'))
671 return STATUS_INVALID_DEVICE_REQUEST
;
675 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
676 if (!NT_SUCCESS(Status
))
678 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
682 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
683 Status
= ObQueryNameString(
684 PhysicalDeviceObject
,
686 sizeof(PdoNameInfoBuffer
),
688 if (!NT_SUCCESS(Status
))
690 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
693 ASSERT(PdoNameInfo
->Name
.Length
);
695 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
696 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
697 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
698 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
699 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
701 BaseKeyName
.Buffer
= ExAllocatePool(
703 BaseKeyName
.MaximumLength
);
704 if (!BaseKeyName
.Buffer
)
706 DPRINT("ExAllocatePool() failed\n");
707 return STATUS_INSUFFICIENT_RESOURCES
;
709 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
710 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
712 /* Create BaseKeyName key in registry */
713 InitializeObjectAttributes(
716 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
717 NULL
, /* RootDirectory */
718 NULL
); /* SecurityDescriptor */
720 Status
= ZwCreateKey(
727 NULL
); /* Disposition */
729 if (!NT_SUCCESS(Status
))
731 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
732 ExFreePool(BaseKeyName
.Buffer
);
736 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
737 InterfaceKeyName
.Length
= 0;
738 InterfaceKeyName
.MaximumLength
=
739 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
740 InstancePath
->Length
+
741 sizeof(WCHAR
) + /* 1 = size of # */
743 InterfaceKeyName
.Buffer
= ExAllocatePool(
745 InterfaceKeyName
.MaximumLength
);
746 if (!InterfaceKeyName
.Buffer
)
748 DPRINT("ExAllocatePool() failed\n");
749 return STATUS_INSUFFICIENT_RESOURCES
;
752 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
753 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
754 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
755 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
757 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
758 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
760 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
761 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
763 /* Create the interface key in registry */
764 InitializeObjectAttributes(
767 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
769 NULL
); /* SecurityDescriptor */
771 Status
= ZwCreateKey(
778 NULL
); /* Disposition */
780 if (!NT_SUCCESS(Status
))
782 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
784 ExFreePool(BaseKeyName
.Buffer
);
788 /* Write DeviceInstance entry. Value is InstancePath */
789 Status
= ZwSetValueKey(
794 InstancePath
->Buffer
,
795 InstancePath
->Length
);
796 if (!NT_SUCCESS(Status
))
798 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
799 ZwClose(InterfaceKey
);
801 ExFreePool(InterfaceKeyName
.Buffer
);
802 ExFreePool(BaseKeyName
.Buffer
);
806 /* Create subkey. Name is #ReferenceString */
807 SubKeyName
.Length
= 0;
808 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
809 if (ReferenceString
&& ReferenceString
->Length
)
810 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
811 SubKeyName
.Buffer
= ExAllocatePool(
813 SubKeyName
.MaximumLength
);
814 if (!SubKeyName
.Buffer
)
816 DPRINT("ExAllocatePool() failed\n");
817 ZwClose(InterfaceKey
);
819 ExFreePool(InterfaceKeyName
.Buffer
);
820 ExFreePool(BaseKeyName
.Buffer
);
821 return STATUS_INSUFFICIENT_RESOURCES
;
823 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
824 if (ReferenceString
&& ReferenceString
->Length
)
825 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
827 /* Create SubKeyName key in registry */
828 InitializeObjectAttributes(
831 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
832 InterfaceKey
, /* RootDirectory */
833 NULL
); /* SecurityDescriptor */
835 Status
= ZwCreateKey(
842 NULL
); /* Disposition */
844 if (!NT_SUCCESS(Status
))
846 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
847 ZwClose(InterfaceKey
);
849 ExFreePool(InterfaceKeyName
.Buffer
);
850 ExFreePool(BaseKeyName
.Buffer
);
854 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
855 SymbolicLinkName
->Length
= 0;
856 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
857 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
858 + InstancePath
->Length
859 + sizeof(WCHAR
) /* 1 = size of # */
861 + sizeof(WCHAR
); /* final NULL */
862 if (ReferenceString
&& ReferenceString
->Length
)
863 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
864 SymbolicLinkName
->Buffer
= ExAllocatePool(
866 SymbolicLinkName
->MaximumLength
);
867 if (!SymbolicLinkName
->Buffer
)
869 DPRINT("ExAllocatePool() failed\n");
871 ZwClose(InterfaceKey
);
873 ExFreePool(InterfaceKeyName
.Buffer
);
874 ExFreePool(SubKeyName
.Buffer
);
875 ExFreePool(BaseKeyName
.Buffer
);
876 return STATUS_INSUFFICIENT_RESOURCES
;
878 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
879 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
880 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
881 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
883 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
884 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
886 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
887 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
888 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
890 /* Create symbolic link */
891 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
892 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
893 if (!NT_SUCCESS(Status
) && ReferenceString
== NULL
)
895 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
897 ZwClose(InterfaceKey
);
899 ExFreePool(SubKeyName
.Buffer
);
900 ExFreePool(InterfaceKeyName
.Buffer
);
901 ExFreePool(BaseKeyName
.Buffer
);
902 ExFreePool(SymbolicLinkName
->Buffer
);
906 if (ReferenceString
&& ReferenceString
->Length
)
908 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
909 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
911 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
913 /* Write symbolic link name in registry */
914 SymbolicLinkName
->Buffer
[1] = '\\';
915 Status
= ZwSetValueKey(
920 SymbolicLinkName
->Buffer
,
921 SymbolicLinkName
->Length
);
922 if (!NT_SUCCESS(Status
))
924 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
925 ExFreePool(SymbolicLinkName
->Buffer
);
929 SymbolicLinkName
->Buffer
[1] = '?';
933 ZwClose(InterfaceKey
);
935 ExFreePool(SubKeyName
.Buffer
);
936 ExFreePool(InterfaceKeyName
.Buffer
);
937 ExFreePool(BaseKeyName
.Buffer
);
943 * @name IoSetDeviceInterfaceState
946 * Enables or disables an instance of a previously registered device
950 * @param SymbolicLinkName
951 * Pointer to the string identifying instance to enable or disable
954 * TRUE = enable, FALSE = disable
956 * @return Usual NTSTATUS
958 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
964 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
967 PDEVICE_OBJECT PhysicalDeviceObject
;
968 PFILE_OBJECT FileObject
;
969 UNICODE_STRING GuidString
;
970 UNICODE_STRING SymLink
;
971 PWCHAR StartPosition
;
977 if (SymbolicLinkName
== NULL
)
978 return STATUS_INVALID_PARAMETER_1
;
980 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
982 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
983 /* Get GUID from SymbolicLinkName */
984 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
985 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
986 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
988 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
989 return STATUS_INVALID_PARAMETER_1
;
991 GuidString
.Buffer
= StartPosition
;
992 GuidString
.MaximumLength
= GuidString
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
);
994 SymLink
.Buffer
= SymbolicLinkName
->Buffer
;
995 SymLink
.MaximumLength
= SymLink
.Length
= (USHORT
)((ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)SymLink
.Buffer
);
996 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
997 /* Get pointer to the PDO */
998 Status
= IoGetDeviceObjectPointer(
1000 0, /* DesiredAccess */
1002 &PhysicalDeviceObject
);
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
1009 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
1010 IopNotifyPlugPlayNotification(
1011 PhysicalDeviceObject
,
1012 EventCategoryDeviceInterfaceChange
,
1015 (PVOID
)SymbolicLinkName
);
1017 ObDereferenceObject(FileObject
);
1018 DPRINT("Status %x\n", Status
);
1019 return STATUS_SUCCESS
;