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 ******************************************************************/
17 #include <internal/debug.h>
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,};
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
= 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
= 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
403 InitializeObjectAttributes(
406 OBJ_CASE_INSENSITIVE
,
413 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
415 /* That's OK. The key doesn't exist (yet) because
416 * the interface is not activated.
418 goto NextReferenceString
;
420 else if (!NT_SUCCESS(Status
))
422 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
425 /* FIXME: Read the Linked value
426 * If it doesn't exist => ERROR
427 * If it is not a REG_DWORD or Size != sizeof(ULONG) => ERROR
428 * If its value is 0, go to NextReferenceString
429 * At the moment, do as if it is active...
431 DPRINT1("Checking if device is enabled is not implemented yet!\n");
434 /* Read the SymbolicLink string and add it into SymbolicLinkList */
435 Status
= ZwQueryValueKey(
438 KeyValuePartialInformation
,
442 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
)
444 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
447 bip
= ExAllocatePool(PagedPool
, Size
);
450 DPRINT("ExAllocatePool() failed\n");
451 Status
= STATUS_INSUFFICIENT_RESOURCES
;
454 Status
= ZwQueryValueKey(
457 KeyValuePartialInformation
,
461 if (!NT_SUCCESS(Status
))
463 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
466 else if (bip
->Type
!= REG_SZ
)
468 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip
->Type
, REG_SZ
);
469 Status
= STATUS_UNSUCCESSFUL
;
472 else if (bip
->DataLength
< 5 * sizeof(WCHAR
))
474 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip
->DataLength
< 5 * sizeof(WCHAR
));
475 Status
= STATUS_UNSUCCESSFUL
;
478 KeyName
.Length
= KeyName
.MaximumLength
= bip
->DataLength
- 4 * sizeof(WCHAR
);
479 KeyName
.Buffer
= &((PWSTR
)bip
->Data
)[4];
480 if (KeyName
.Length
&& KeyName
.Buffer
[KeyName
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
)
482 /* Remove trailing NULL */
483 KeyName
.Length
-= sizeof(WCHAR
);
486 /* Add new symbolic link to symbolic link list */
487 if (ReturnBuffer
.Length
+ KeyName
.Length
+ sizeof(WCHAR
) > ReturnBuffer
.MaximumLength
)
490 ReturnBuffer
.MaximumLength
= max(ReturnBuffer
.MaximumLength
* 2, ReturnBuffer
.Length
+ KeyName
.Length
+ 2 * sizeof(WCHAR
));
491 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
494 DPRINT("ExAllocatePool() failed\n");
495 Status
= STATUS_INSUFFICIENT_RESOURCES
;
498 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
499 ExFreePool(ReturnBuffer
.Buffer
);
500 ReturnBuffer
.Buffer
= NewBuffer
;
502 DPRINT("Adding symbolic link %wZ\n", &KeyName
);
503 Status
= RtlAppendUnicodeStringToString(&ReturnBuffer
, &KeyName
);
504 if (!NT_SUCCESS(Status
))
506 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
509 /* RtlAppendUnicodeStringToString added a NULL at the end of the
510 * destination string, but didn't increase the Length field.
513 ReturnBuffer
.Length
+= sizeof(WCHAR
);
516 ExFreePool(ReferenceBi
);
520 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
522 ZwClose(ReferenceKey
);
523 ReferenceKey
= INVALID_HANDLE_VALUE
;
525 if (ControlKey
!= INVALID_HANDLE_VALUE
)
528 ControlKey
= INVALID_HANDLE_VALUE
;
533 /* No need to go further, as we already have found what we searched */
537 ExFreePool(DeviceBi
);
540 DeviceKey
= INVALID_HANDLE_VALUE
;
543 /* Add final NULL to ReturnBuffer */
544 if (ReturnBuffer
.Length
>= ReturnBuffer
.MaximumLength
)
547 ReturnBuffer
.MaximumLength
+= sizeof(WCHAR
);
548 NewBuffer
= ExAllocatePool(PagedPool
, ReturnBuffer
.MaximumLength
);
551 DPRINT("ExAllocatePool() failed\n");
552 Status
= STATUS_INSUFFICIENT_RESOURCES
;
555 RtlCopyMemory(NewBuffer
, ReturnBuffer
.Buffer
, ReturnBuffer
.Length
);
556 ExFreePool(ReturnBuffer
.Buffer
);
557 ReturnBuffer
.Buffer
= NewBuffer
;
559 ReturnBuffer
.Buffer
[ReturnBuffer
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
560 *SymbolicLinkList
= ReturnBuffer
.Buffer
;
561 Status
= STATUS_SUCCESS
;
564 if (!NT_SUCCESS(Status
))
565 ExFreePool(ReturnBuffer
.Buffer
);
566 if (InterfaceKey
!= INVALID_HANDLE_VALUE
)
567 ZwClose(InterfaceKey
);
568 if (DeviceKey
!= INVALID_HANDLE_VALUE
)
570 if (ReferenceKey
!= INVALID_HANDLE_VALUE
)
571 ZwClose(ReferenceKey
);
572 if (ControlKey
!= INVALID_HANDLE_VALUE
)
574 ExFreePool(DeviceBi
);
575 ExFreePool(ReferenceBi
);
581 * @name IoRegisterDeviceInterface
584 * Registers a device interface class, if it has not been previously registered,
585 * and creates a new instance of the interface class, which a driver can
586 * subsequently enable for use by applications or other system components.
589 * @param PhysicalDeviceObject
590 * Points to an optional PDO that narrows the search to only the
591 * device interfaces of the device represented by the PDO
593 * @param InterfaceClassGuid
594 * Points to a class GUID specifying the device interface class
596 * @param ReferenceString
597 * Optional parameter, pointing to a unicode string. For a full
598 * description of this rather rarely used param (usually drivers
599 * pass NULL here) see WDK
601 * @param SymbolicLinkName
602 * Pointer to the resulting unicode string
604 * @return Usual NTSTATUS
606 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
612 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject
,
613 IN CONST GUID
*InterfaceClassGuid
,
614 IN PUNICODE_STRING ReferenceString OPTIONAL
,
615 OUT PUNICODE_STRING SymbolicLinkName
)
617 PUNICODE_STRING InstancePath
;
618 UNICODE_STRING GuidString
;
619 UNICODE_STRING SubKeyName
;
620 UNICODE_STRING InterfaceKeyName
;
621 UNICODE_STRING BaseKeyName
;
622 UCHAR PdoNameInfoBuffer
[sizeof(OBJECT_NAME_INFORMATION
) + (256 * sizeof(WCHAR
))];
623 POBJECT_NAME_INFORMATION PdoNameInfo
= (POBJECT_NAME_INFORMATION
)PdoNameInfoBuffer
;
624 UNICODE_STRING DeviceInstance
= RTL_CONSTANT_STRING(L
"DeviceInstance");
625 UNICODE_STRING SymbolicLink
= RTL_CONSTANT_STRING(L
"SymbolicLink");
630 OBJECT_ATTRIBUTES ObjectAttributes
;
633 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension
;
635 ASSERT_IRQL(PASSIVE_LEVEL
);
637 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n",
638 PhysicalDeviceObject
, ReferenceString
);
640 /* Parameters must pass three border of checks */
641 DeviceObjectExtension
= (PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
;
643 /* 1st level: Presence of a Device Node */
644 if (DeviceObjectExtension
->DeviceNode
== NULL
)
646 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject
);
647 return STATUS_INVALID_DEVICE_REQUEST
;
650 /* 2nd level: Presence of an non-zero length InstancePath */
651 if (DeviceObjectExtension
->DeviceNode
->InstancePath
.Length
== 0)
653 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject
);
654 return STATUS_INVALID_DEVICE_REQUEST
;
657 /* 3rd level: Optional, based on WDK documentation */
658 if (ReferenceString
!= NULL
)
660 /* Reference string must not contain path-separator symbols */
661 for (i
= 0; i
< ReferenceString
->Length
/ sizeof(WCHAR
); i
++)
663 if ((ReferenceString
->Buffer
[i
] == '\\') ||
664 (ReferenceString
->Buffer
[i
] == '/'))
665 return STATUS_INVALID_DEVICE_REQUEST
;
669 Status
= RtlStringFromGUID(InterfaceClassGuid
, &GuidString
);
670 if (!NT_SUCCESS(Status
))
672 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status
);
676 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */
677 Status
= ObQueryNameString(
678 PhysicalDeviceObject
,
680 sizeof(PdoNameInfoBuffer
),
682 if (!NT_SUCCESS(Status
))
684 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status
);
687 ASSERT(PdoNameInfo
->Name
.Length
);
689 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
690 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
);
691 InstancePath
= &((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
->InstancePath
;
692 BaseKeyName
.Length
= wcslen(BaseKeyString
) * sizeof(WCHAR
);
693 BaseKeyName
.MaximumLength
= BaseKeyName
.Length
695 BaseKeyName
.Buffer
= ExAllocatePool(
697 BaseKeyName
.MaximumLength
);
698 if (!BaseKeyName
.Buffer
)
700 DPRINT("ExAllocatePool() failed\n");
701 return STATUS_INSUFFICIENT_RESOURCES
;
703 wcscpy(BaseKeyName
.Buffer
, BaseKeyString
);
704 RtlAppendUnicodeStringToString(&BaseKeyName
, &GuidString
);
706 /* Create BaseKeyName key in registry */
707 InitializeObjectAttributes(
710 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
711 NULL
, /* RootDirectory */
712 NULL
); /* SecurityDescriptor */
714 Status
= ZwCreateKey(
721 NULL
); /* Disposition */
723 if (!NT_SUCCESS(Status
))
725 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
726 ExFreePool(BaseKeyName
.Buffer
);
730 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */
731 InterfaceKeyName
.Length
= 0;
732 InterfaceKeyName
.MaximumLength
=
733 4 * sizeof(WCHAR
) + /* 4 = size of ##?# */
734 InstancePath
->Length
+
735 sizeof(WCHAR
) + /* 1 = size of # */
737 InterfaceKeyName
.Buffer
= ExAllocatePool(
739 InterfaceKeyName
.MaximumLength
);
740 if (!InterfaceKeyName
.Buffer
)
742 DPRINT("ExAllocatePool() failed\n");
743 return STATUS_INSUFFICIENT_RESOURCES
;
746 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"##?#");
747 StartIndex
= InterfaceKeyName
.Length
/ sizeof(WCHAR
);
748 RtlAppendUnicodeStringToString(&InterfaceKeyName
, InstancePath
);
749 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
751 if (InterfaceKeyName
.Buffer
[StartIndex
+ i
] == '\\')
752 InterfaceKeyName
.Buffer
[StartIndex
+ i
] = '#';
754 RtlAppendUnicodeToString(&InterfaceKeyName
, L
"#");
755 RtlAppendUnicodeStringToString(&InterfaceKeyName
, &GuidString
);
757 /* Create the interface key in registry */
758 InitializeObjectAttributes(
761 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
| OBJ_OPENIF
,
763 NULL
); /* SecurityDescriptor */
765 Status
= ZwCreateKey(
772 NULL
); /* Disposition */
774 if (!NT_SUCCESS(Status
))
776 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
778 ExFreePool(BaseKeyName
.Buffer
);
782 /* Write DeviceInstance entry. Value is InstancePath */
783 Status
= ZwSetValueKey(
788 InstancePath
->Buffer
,
789 InstancePath
->Length
);
790 if (!NT_SUCCESS(Status
))
792 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
793 ZwClose(InterfaceKey
);
795 ExFreePool(InterfaceKeyName
.Buffer
);
796 ExFreePool(BaseKeyName
.Buffer
);
800 /* Create subkey. Name is #ReferenceString */
801 SubKeyName
.Length
= 0;
802 SubKeyName
.MaximumLength
= sizeof(WCHAR
);
803 if (ReferenceString
&& ReferenceString
->Length
)
804 SubKeyName
.MaximumLength
+= ReferenceString
->Length
;
805 SubKeyName
.Buffer
= ExAllocatePool(
807 SubKeyName
.MaximumLength
);
808 if (!SubKeyName
.Buffer
)
810 DPRINT("ExAllocatePool() failed\n");
811 ZwClose(InterfaceKey
);
813 ExFreePool(InterfaceKeyName
.Buffer
);
814 ExFreePool(BaseKeyName
.Buffer
);
815 return STATUS_INSUFFICIENT_RESOURCES
;
817 RtlAppendUnicodeToString(&SubKeyName
, L
"#");
818 if (ReferenceString
&& ReferenceString
->Length
)
819 RtlAppendUnicodeStringToString(&SubKeyName
, ReferenceString
);
821 /* Create SubKeyName key in registry */
822 InitializeObjectAttributes(
825 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
826 InterfaceKey
, /* RootDirectory */
827 NULL
); /* SecurityDescriptor */
829 Status
= ZwCreateKey(
836 NULL
); /* Disposition */
838 if (!NT_SUCCESS(Status
))
840 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
841 ZwClose(InterfaceKey
);
843 ExFreePool(InterfaceKeyName
.Buffer
);
844 ExFreePool(BaseKeyName
.Buffer
);
848 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
849 SymbolicLinkName
->Length
= 0;
850 SymbolicLinkName
->MaximumLength
= SymbolicLinkName
->Length
851 + 4 * sizeof(WCHAR
) /* 4 = size of \??\ */
852 + InstancePath
->Length
853 + sizeof(WCHAR
) /* 1 = size of # */
855 + sizeof(WCHAR
); /* final NULL */
856 if (ReferenceString
&& ReferenceString
->Length
)
857 SymbolicLinkName
->MaximumLength
+= sizeof(WCHAR
) + ReferenceString
->Length
;
858 SymbolicLinkName
->Buffer
= ExAllocatePool(
860 SymbolicLinkName
->MaximumLength
);
861 if (!SymbolicLinkName
->Buffer
)
863 DPRINT("ExAllocatePool() failed\n");
865 ZwClose(InterfaceKey
);
867 ExFreePool(InterfaceKeyName
.Buffer
);
868 ExFreePool(SubKeyName
.Buffer
);
869 ExFreePool(BaseKeyName
.Buffer
);
870 return STATUS_INSUFFICIENT_RESOURCES
;
872 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\??\\");
873 StartIndex
= SymbolicLinkName
->Length
/ sizeof(WCHAR
);
874 RtlAppendUnicodeStringToString(SymbolicLinkName
, InstancePath
);
875 for (i
= 0; i
< InstancePath
->Length
/ sizeof(WCHAR
); i
++)
877 if (SymbolicLinkName
->Buffer
[StartIndex
+ i
] == '\\')
878 SymbolicLinkName
->Buffer
[StartIndex
+ i
] = '#';
880 RtlAppendUnicodeToString(SymbolicLinkName
, L
"#");
881 RtlAppendUnicodeStringToString(SymbolicLinkName
, &GuidString
);
882 if (ReferenceString
&& ReferenceString
->Length
)
884 RtlAppendUnicodeToString(SymbolicLinkName
, L
"\\");
885 RtlAppendUnicodeStringToString(SymbolicLinkName
, ReferenceString
);
887 SymbolicLinkName
->Buffer
[SymbolicLinkName
->Length
/sizeof(WCHAR
)] = L
'\0';
889 /* Create symbolic link */
890 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName
, &PdoNameInfo
->Name
);
891 Status
= IoCreateSymbolicLink(SymbolicLinkName
, &PdoNameInfo
->Name
);
892 if (!NT_SUCCESS(Status
))
894 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status
);
896 ZwClose(InterfaceKey
);
898 ExFreePool(SubKeyName
.Buffer
);
899 ExFreePool(InterfaceKeyName
.Buffer
);
900 ExFreePool(BaseKeyName
.Buffer
);
901 ExFreePool(SymbolicLinkName
->Buffer
);
905 /* Write symbolic link name in registry */
906 SymbolicLinkName
->Buffer
[1] = '\\';
907 Status
= ZwSetValueKey(
912 SymbolicLinkName
->Buffer
,
913 SymbolicLinkName
->Length
);
914 if (!NT_SUCCESS(Status
))
916 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
917 ExFreePool(SymbolicLinkName
->Buffer
);
919 SymbolicLinkName
->Buffer
[1] = '?';
922 ZwClose(InterfaceKey
);
924 ExFreePool(SubKeyName
.Buffer
);
925 ExFreePool(InterfaceKeyName
.Buffer
);
926 ExFreePool(BaseKeyName
.Buffer
);
932 * @name IoSetDeviceInterfaceState
935 * Enables or disables an instance of a previously registered device
939 * @param SymbolicLinkName
940 * Pointer to the string identifying instance to enable or disable
943 * TRUE = enable, FALSE = disable
945 * @return Usual NTSTATUS
947 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a
953 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName
,
956 PDEVICE_OBJECT PhysicalDeviceObject
;
957 PFILE_OBJECT FileObject
;
958 UNICODE_STRING GuidString
;
959 PWCHAR StartPosition
;
964 if (SymbolicLinkName
== NULL
)
965 return STATUS_INVALID_PARAMETER_1
;
967 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName
, Enable
);
969 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
970 /* Get GUID from SymbolicLinkName */
971 StartPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'{');
972 EndPosition
= wcschr(SymbolicLinkName
->Buffer
, L
'}');
973 if (!StartPosition
||!EndPosition
|| StartPosition
> EndPosition
)
975 DPRINT("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n");
976 return STATUS_INVALID_PARAMETER_1
;
978 GuidString
.Buffer
= StartPosition
;
979 GuidString
.MaximumLength
= GuidString
.Length
= (ULONG_PTR
)(EndPosition
+ 1) - (ULONG_PTR
)StartPosition
;
981 /* Get pointer to the PDO */
982 Status
= IoGetDeviceObjectPointer(
984 0, /* DesiredAccess */
986 &PhysicalDeviceObject
);
987 if (!NT_SUCCESS(Status
))
989 DPRINT("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status
);
993 EventGuid
= Enable
? &GUID_DEVICE_INTERFACE_ARRIVAL
: &GUID_DEVICE_INTERFACE_REMOVAL
;
994 IopNotifyPlugPlayNotification(
995 PhysicalDeviceObject
,
996 EventCategoryDeviceInterfaceChange
,
999 (PVOID
)SymbolicLinkName
);
1001 ObDereferenceObject(FileObject
);
1003 return STATUS_SUCCESS
;