KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / io / deviface.c
1 /* $Id:$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/deviface.c
6 * PURPOSE: Device interface functions
7 *
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Matthew Brace (ismarc@austin.rr.com)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\";
22
23 /*
24 * @unimplemented
25 */
26
27 NTSTATUS STDCALL
28 IoOpenDeviceInterfaceRegistryKey(
29 IN PUNICODE_STRING SymbolicLinkName,
30 IN ACCESS_MASK DesiredAccess,
31 OUT PHANDLE DeviceInterfaceKey)
32 {
33 return STATUS_NOT_IMPLEMENTED;
34 }
35
36 /*
37 * @unimplemented
38 */
39
40 NTSTATUS STDCALL
41 IoGetDeviceInterfaceAlias(
42 IN PUNICODE_STRING SymbolicLinkName,
43 IN CONST GUID *AliasInterfaceClassGuid,
44 OUT PUNICODE_STRING AliasSymbolicLinkName)
45 {
46 return STATUS_NOT_IMPLEMENTED;
47 }
48
49 /*
50 * IoGetDeviceInterfaces
51 *
52 * Returns a list of device interfaces of a particular device interface class.
53 *
54 * Parameters
55 * InterfaceClassGuid
56 * Points to a class GUID specifying the device interface class.
57 *
58 * PhysicalDeviceObject
59 * Points to an optional PDO that narrows the search to only the
60 * device interfaces of the device represented by the PDO.
61 *
62 * Flags
63 * Specifies flags that modify the search for device interfaces. The
64 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of
65 * returned symbolic links should contain also disabled device
66 * interfaces in addition to the enabled ones.
67 *
68 * SymbolicLinkList
69 * Points to a character pointer that is filled in on successful return
70 * with a list of unicode strings identifying the device interfaces
71 * that match the search criteria. The newly allocated buffer contains
72 * a list of symbolic link names. Each unicode string in the list is
73 * null-terminated; the end of the whole list is marked by an additional
74 * NULL. The caller is responsible for freeing the buffer (ExFreePool)
75 * when it is no longer needed.
76 * If no device interfaces match the search criteria, this routine
77 * returns STATUS_SUCCESS and the string contains a single NULL
78 * character.
79 *
80 * Status
81 * @implemented
82 *
83 * The parameters PhysicalDeviceObject and Flags aren't correctly
84 * processed. Rest of the cases was tested under Windows(R) XP and
85 * the function worked correctly.
86 */
87
88 NTSTATUS STDCALL
89 IoGetDeviceInterfaces(
90 IN CONST GUID *InterfaceClassGuid,
91 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
92 IN ULONG Flags,
93 OUT PWSTR *SymbolicLinkList)
94 {
95 PWCHAR BaseInterfaceString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
96 UNICODE_STRING GuidString;
97 UNICODE_STRING BaseKeyName;
98 UNICODE_STRING AliasKeyName;
99 UNICODE_STRING SymbolicLink;
100 UNICODE_STRING Control;
101 UNICODE_STRING SubKeyName;
102 UNICODE_STRING SymbolicLinkKeyName;
103 UNICODE_STRING ControlKeyName;
104 UNICODE_STRING TempString;
105 HANDLE InterfaceKey;
106 HANDLE SubKey;
107 HANDLE SymbolicLinkKey;
108 PKEY_FULL_INFORMATION fip;
109 PKEY_FULL_INFORMATION bfip = NULL;
110 PKEY_BASIC_INFORMATION bip;
111 PKEY_VALUE_PARTIAL_INFORMATION vpip = NULL;
112 PWCHAR SymLinkList = NULL;
113 ULONG SymLinkListSize = 0;
114 NTSTATUS Status;
115 ULONG Size = 0;
116 ULONG i = 0;
117 ULONG j = 0;
118 OBJECT_ATTRIBUTES ObjectAttributes;
119
120 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
121 if (!NT_SUCCESS(Status))
122 {
123 DPRINT("RtlStringFromGUID() Failed.\n");
124 return STATUS_INVALID_HANDLE;
125 }
126
127 RtlInitUnicodeString(&AliasKeyName, BaseInterfaceString);
128 RtlInitUnicodeString(&SymbolicLink, L"SymbolicLink");
129 RtlInitUnicodeString(&Control, L"\\Control");
130 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
131 BaseKeyName.MaximumLength = BaseKeyName.Length + (38 * sizeof(WCHAR));
132 BaseKeyName.Buffer = ExAllocatePool(
133 NonPagedPool,
134 BaseKeyName.MaximumLength);
135 ASSERT(BaseKeyName.Buffer != NULL);
136 wcscpy(BaseKeyName.Buffer, BaseKeyString);
137 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
138
139 if (PhysicalDeviceObject)
140 {
141 WCHAR GuidBuffer[40];
142 UNICODE_STRING PdoGuidString;
143
144 RtlFreeUnicodeString(&BaseKeyName);
145
146 IoGetDeviceProperty(
147 PhysicalDeviceObject,
148 DevicePropertyClassGuid,
149 sizeof(GuidBuffer),
150 GuidBuffer,
151 &Size);
152
153 RtlInitUnicodeString(&PdoGuidString, GuidBuffer);
154 if (RtlCompareUnicodeString(&GuidString, &PdoGuidString, TRUE))
155 {
156 DPRINT("Inconsistent Guid's asked for in IoGetDeviceInterfaces()\n");
157 return STATUS_INVALID_HANDLE;
158 }
159
160 DPRINT("IoGetDeviceInterfaces() called with PDO, not implemented.\n");
161 return STATUS_NOT_IMPLEMENTED;
162 }
163 else
164 {
165 InitializeObjectAttributes(
166 &ObjectAttributes,
167 &BaseKeyName,
168 OBJ_CASE_INSENSITIVE,
169 NULL,
170 NULL);
171
172 Status = ZwOpenKey(
173 &InterfaceKey,
174 KEY_READ,
175 &ObjectAttributes);
176
177 if (!NT_SUCCESS(Status))
178 {
179 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
180 RtlFreeUnicodeString(&BaseKeyName);
181 return Status;
182 }
183
184 Status = ZwQueryKey(
185 InterfaceKey,
186 KeyFullInformation,
187 NULL,
188 0,
189 &Size);
190
191 if (Status != STATUS_BUFFER_TOO_SMALL)
192 {
193 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
194 RtlFreeUnicodeString(&BaseKeyName);
195 ZwClose(InterfaceKey);
196 return Status;
197 }
198
199 fip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
200 ASSERT(fip != NULL);
201
202 Status = ZwQueryKey(
203 InterfaceKey,
204 KeyFullInformation,
205 fip,
206 Size,
207 &Size);
208
209 if (!NT_SUCCESS(Status))
210 {
211 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
212 ExFreePool(fip);
213 RtlFreeUnicodeString(&BaseKeyName);
214 ZwClose(InterfaceKey);
215 return Status;
216 }
217
218 for (; i < fip->SubKeys; i++)
219 {
220 Status = ZwEnumerateKey(
221 InterfaceKey,
222 i,
223 KeyBasicInformation,
224 NULL,
225 0,
226 &Size);
227
228 if (Status != STATUS_BUFFER_TOO_SMALL)
229 {
230 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
231 ExFreePool(fip);
232 if (SymLinkList != NULL)
233 ExFreePool(SymLinkList);
234 RtlFreeUnicodeString(&BaseKeyName);
235 ZwClose(InterfaceKey);
236 return Status;
237 }
238
239 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
240 ASSERT(bip != NULL);
241
242 Status = ZwEnumerateKey(
243 InterfaceKey,
244 i,
245 KeyBasicInformation,
246 bip,
247 Size,
248 &Size);
249
250 if (!NT_SUCCESS(Status))
251 {
252 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
253 ExFreePool(fip);
254 ExFreePool(bip);
255 if (SymLinkList != NULL)
256 ExFreePool(SymLinkList);
257 RtlFreeUnicodeString(&BaseKeyName);
258 ZwClose(InterfaceKey);
259 return Status;
260 }
261
262 SubKeyName.Length = 0;
263 SubKeyName.MaximumLength = BaseKeyName.Length + bip->NameLength + sizeof(WCHAR);
264 SubKeyName.Buffer = ExAllocatePool(NonPagedPool, SubKeyName.MaximumLength);
265 ASSERT(SubKeyName.Buffer != NULL);
266 TempString.Length = TempString.MaximumLength = bip->NameLength;
267 TempString.Buffer = bip->Name;
268 RtlCopyUnicodeString(&SubKeyName, &BaseKeyName);
269 RtlAppendUnicodeToString(&SubKeyName, L"\\");
270 RtlAppendUnicodeStringToString(&SubKeyName, &TempString);
271
272 ExFreePool(bip);
273
274 InitializeObjectAttributes(
275 &ObjectAttributes,
276 &SubKeyName,
277 OBJ_CASE_INSENSITIVE,
278 NULL,
279 NULL);
280
281 Status = ZwOpenKey(
282 &SubKey,
283 KEY_READ,
284 &ObjectAttributes);
285
286 if (!NT_SUCCESS(Status))
287 {
288 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
289 ExFreePool(fip);
290 if (SymLinkList != NULL)
291 ExFreePool(SymLinkList);
292 RtlFreeUnicodeString(&SubKeyName);
293 RtlFreeUnicodeString(&BaseKeyName);
294 ZwClose(InterfaceKey);
295 return Status;
296 }
297
298 Status = ZwQueryKey(
299 SubKey,
300 KeyFullInformation,
301 NULL,
302 0,
303 &Size);
304
305 if (Status != STATUS_BUFFER_TOO_SMALL)
306 {
307 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
308 ExFreePool(fip);
309 RtlFreeUnicodeString(&BaseKeyName);
310 RtlFreeUnicodeString(&SubKeyName);
311 ZwClose(SubKey);
312 ZwClose(InterfaceKey);
313 return Status;
314 }
315
316 bfip = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
317 ASSERT(bfip != NULL);
318
319 Status = ZwQueryKey(
320 SubKey,
321 KeyFullInformation,
322 bfip,
323 Size,
324 &Size);
325
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("ZwQueryKey() Failed. (0x%X)\n", Status);
329 ExFreePool(fip);
330 RtlFreeUnicodeString(&SubKeyName);
331 RtlFreeUnicodeString(&BaseKeyName);
332 ZwClose(SubKey);
333 ZwClose(InterfaceKey);
334 return Status;
335 }
336
337 for(j = 0; j < bfip->SubKeys; j++)
338 {
339 Status = ZwEnumerateKey(
340 SubKey,
341 j,
342 KeyBasicInformation,
343 NULL,
344 0,
345 &Size);
346
347 if (Status == STATUS_NO_MORE_ENTRIES)
348 continue;
349
350 if (Status != STATUS_BUFFER_TOO_SMALL)
351 {
352 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
353 ExFreePool(bfip);
354 ExFreePool(fip);
355 if (SymLinkList != NULL)
356 ExFreePool(SymLinkList);
357 RtlFreeUnicodeString(&SubKeyName);
358 RtlFreeUnicodeString(&BaseKeyName);
359 ZwClose(SubKey);
360 ZwClose(InterfaceKey);
361 return Status;
362 }
363
364 bip = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, Size);
365 ASSERT(bip != NULL);
366
367 Status = ZwEnumerateKey(
368 SubKey,
369 j,
370 KeyBasicInformation,
371 bip,
372 Size,
373 &Size);
374
375 if (!NT_SUCCESS(Status))
376 {
377 DPRINT("ZwEnumerateKey() Failed.(0x%X)\n", Status);
378 ExFreePool(fip);
379 ExFreePool(bfip);
380 ExFreePool(bip);
381 if (SymLinkList != NULL)
382 ExFreePool(SymLinkList);
383 RtlFreeUnicodeString(&SubKeyName);
384 RtlFreeUnicodeString(&BaseKeyName);
385 ZwClose(SubKey);
386 ZwClose(InterfaceKey);
387 return Status;
388 }
389
390 if (!wcsncmp(bip->Name, L"Control", bip->NameLength))
391 {
392 continue;
393 }
394
395 SymbolicLinkKeyName.Length = 0;
396 SymbolicLinkKeyName.MaximumLength = SubKeyName.Length + bip->NameLength + sizeof(WCHAR);
397 SymbolicLinkKeyName.Buffer = ExAllocatePool(NonPagedPool, SymbolicLinkKeyName.MaximumLength);
398 ASSERT(SymbolicLinkKeyName.Buffer != NULL);
399 TempString.Length = TempString.MaximumLength = bip->NameLength;
400 TempString.Buffer = bip->Name;
401 RtlCopyUnicodeString(&SymbolicLinkKeyName, &SubKeyName);
402 RtlAppendUnicodeToString(&SymbolicLinkKeyName, L"\\");
403 RtlAppendUnicodeStringToString(&SymbolicLinkKeyName, &TempString);
404
405 ControlKeyName.Length = 0;
406 ControlKeyName.MaximumLength = SymbolicLinkKeyName.Length + Control.Length + sizeof(WCHAR);
407 ControlKeyName.Buffer = ExAllocatePool(NonPagedPool, ControlKeyName.MaximumLength);
408 ASSERT(ControlKeyName.Buffer != NULL);
409 RtlCopyUnicodeString(&ControlKeyName, &SymbolicLinkKeyName);
410 RtlAppendUnicodeStringToString(&ControlKeyName, &Control);
411
412 ExFreePool(bip);
413
414 InitializeObjectAttributes(
415 &ObjectAttributes,
416 &SymbolicLinkKeyName,
417 OBJ_CASE_INSENSITIVE,
418 NULL,
419 NULL);
420
421 Status = ZwOpenKey(
422 &SymbolicLinkKey,
423 KEY_READ,
424 &ObjectAttributes);
425
426 if (!NT_SUCCESS(Status))
427 {
428 DPRINT("ZwOpenKey() Failed. (0x%X)\n", Status);
429 ExFreePool(fip);
430 ExFreePool(bfip);
431 if (SymLinkList != NULL)
432 ExFreePool(SymLinkList);
433 RtlFreeUnicodeString(&SymbolicLinkKeyName);
434 RtlFreeUnicodeString(&SubKeyName);
435 RtlFreeUnicodeString(&BaseKeyName);
436 ZwClose(SubKey);
437 ZwClose(InterfaceKey);
438 return Status;
439 }
440
441 Status = ZwQueryValueKey(
442 SymbolicLinkKey,
443 &SymbolicLink,
444 KeyValuePartialInformation,
445 NULL,
446 0,
447 &Size);
448
449 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
450 continue;
451
452 if (Status != STATUS_BUFFER_TOO_SMALL)
453 {
454 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
455 ExFreePool(fip);
456 ExFreePool(bfip);
457 if (SymLinkList != NULL)
458 ExFreePool(SymLinkList);
459 RtlFreeUnicodeString(&SymbolicLinkKeyName);
460 RtlFreeUnicodeString(&SubKeyName);
461 RtlFreeUnicodeString(&BaseKeyName);
462 ZwClose(SymbolicLinkKey);
463 ZwClose(SubKey);
464 ZwClose(InterfaceKey);
465 return Status;
466 }
467
468 vpip = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, Size);
469 ASSERT(vpip != NULL);
470
471 Status = ZwQueryValueKey(
472 SymbolicLinkKey,
473 &SymbolicLink,
474 KeyValuePartialInformation,
475 vpip,
476 Size,
477 &Size);
478
479 if (!NT_SUCCESS(Status))
480 {
481 DPRINT("ZwQueryValueKey() Failed.(0x%X)\n", Status);
482 ExFreePool(fip);
483 ExFreePool(bfip);
484 ExFreePool(vpip);
485 if (SymLinkList != NULL)
486 ExFreePool(SymLinkList);
487 RtlFreeUnicodeString(&SymbolicLinkKeyName);
488 RtlFreeUnicodeString(&SubKeyName);
489 RtlFreeUnicodeString(&BaseKeyName);
490 ZwClose(SymbolicLinkKey);
491 ZwClose(SubKey);
492 ZwClose(InterfaceKey);
493 return Status;
494 }
495
496 Status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, ControlKeyName.Buffer);
497
498 if (NT_SUCCESS(Status))
499 {
500 /* Put the name in the string here */
501 if (SymLinkList == NULL)
502 {
503 SymLinkListSize = vpip->DataLength;
504 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
505 ASSERT(SymLinkList != NULL);
506 RtlCopyMemory(SymLinkList, vpip->Data, vpip->DataLength);
507 SymLinkList[vpip->DataLength / sizeof(WCHAR)] = 0;
508 SymLinkList[1] = '?';
509 }
510 else
511 {
512 PWCHAR OldSymLinkList;
513 ULONG OldSymLinkListSize;
514 PWCHAR SymLinkListPtr;
515
516 OldSymLinkList = SymLinkList;
517 OldSymLinkListSize = SymLinkListSize;
518 SymLinkListSize += vpip->DataLength;
519 SymLinkList = ExAllocatePool(NonPagedPool, SymLinkListSize + sizeof(WCHAR));
520 ASSERT(SymLinkList != NULL);
521 RtlCopyMemory(SymLinkList, OldSymLinkList, OldSymLinkListSize);
522 ExFreePool(OldSymLinkList);
523 SymLinkListPtr = SymLinkList + (OldSymLinkListSize / sizeof(WCHAR));
524 RtlCopyMemory(SymLinkListPtr, vpip->Data, vpip->DataLength);
525 SymLinkListPtr[vpip->DataLength / sizeof(WCHAR)] = 0;
526 SymLinkListPtr[1] = '?';
527 }
528 }
529
530 RtlFreeUnicodeString(&SymbolicLinkKeyName);
531 RtlFreeUnicodeString(&ControlKeyName);
532 ZwClose(SymbolicLinkKey);
533 }
534
535 ExFreePool(vpip);
536 RtlFreeUnicodeString(&SubKeyName);
537 ZwClose(SubKey);
538 }
539
540 if (SymLinkList != NULL)
541 {
542 SymLinkList[SymLinkListSize / sizeof(WCHAR)] = 0;
543 }
544 else
545 {
546 SymLinkList = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
547 SymLinkList[0] = 0;
548 }
549
550 *SymbolicLinkList = SymLinkList;
551
552 RtlFreeUnicodeString(&BaseKeyName);
553 ZwClose(InterfaceKey);
554 ExFreePool(bfip);
555 ExFreePool(fip);
556 }
557
558 return STATUS_SUCCESS;
559 }
560
561 /*
562 * @implemented
563 */
564
565 NTSTATUS STDCALL
566 IoRegisterDeviceInterface(
567 IN PDEVICE_OBJECT PhysicalDeviceObject,
568 IN CONST GUID *InterfaceClassGuid,
569 IN PUNICODE_STRING ReferenceString OPTIONAL,
570 OUT PUNICODE_STRING SymbolicLinkName)
571 {
572 PUNICODE_STRING InstancePath;
573 UNICODE_STRING GuidString;
574 UNICODE_STRING SubKeyName;
575 UNICODE_STRING BaseKeyName;
576 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance");
577 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink");
578 HANDLE InterfaceKey;
579 HANDLE SubKey;
580 ULONG StartIndex;
581 OBJECT_ATTRIBUTES ObjectAttributes;
582 ULONG i;
583 NTSTATUS Status;
584
585 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString);
586 if (!NT_SUCCESS(Status))
587 {
588 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status);
589 return Status;
590 }
591
592 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\DeviceClasses\{GUID}\##?#ACPI#PNP0501#1#{GUID} */
593 InstancePath = &PhysicalDeviceObject->DeviceObjectExtension->DeviceNode->InstancePath;
594 BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR);
595 BaseKeyName.MaximumLength = BaseKeyName.Length
596 + GuidString.Length
597 + 5 * sizeof(WCHAR) /* 5 = size of \##?# */
598 + InstancePath->Length
599 + sizeof(WCHAR) /* 1 = size of # */
600 + GuidString.Length;
601 BaseKeyName.Buffer = ExAllocatePool(
602 NonPagedPool,
603 BaseKeyName.MaximumLength);
604 if (!BaseKeyName.Buffer)
605 {
606 DPRINT("ExAllocatePool() failed\n");
607 return STATUS_INSUFFICIENT_RESOURCES;
608 }
609 wcscpy(BaseKeyName.Buffer, BaseKeyString);
610 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
611 RtlAppendUnicodeToString(&BaseKeyName, L"\\##?#");
612 StartIndex = BaseKeyName.Length / sizeof(WCHAR);
613 RtlAppendUnicodeStringToString(&BaseKeyName, InstancePath);
614 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
615 {
616 if (BaseKeyName.Buffer[StartIndex + i] == '\\')
617 BaseKeyName.Buffer[StartIndex + i] = '#';
618 }
619 RtlAppendUnicodeToString(&BaseKeyName, L"#");
620 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString);
621
622 /* Create BaseKeyName key in registry */
623 InitializeObjectAttributes(
624 &ObjectAttributes,
625 &BaseKeyName,
626 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF,
627 NULL, /* RootDirectory */
628 NULL); /* SecurityDescriptor */
629
630 Status = ZwCreateKey(
631 &InterfaceKey,
632 KEY_WRITE,
633 &ObjectAttributes,
634 0, /* TileIndex */
635 NULL, /* Class */
636 REG_OPTION_VOLATILE,
637 NULL); /* Disposition */
638
639 if (!NT_SUCCESS(Status))
640 {
641 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
642 ExFreePool(BaseKeyName.Buffer);
643 return Status;
644 }
645
646 /* Write DeviceInstance entry. Value is InstancePath */
647 Status = ZwSetValueKey(
648 InterfaceKey,
649 &DeviceInstance,
650 0, /* TileIndex */
651 REG_SZ,
652 InstancePath->Buffer,
653 InstancePath->Length);
654 if (!NT_SUCCESS(Status))
655 {
656 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
657 ZwClose(InterfaceKey);
658 ExFreePool(BaseKeyName.Buffer);
659 return Status;
660 }
661
662 /* Create subkey. Name is #ReferenceString */
663 SubKeyName.Length = 0;
664 SubKeyName.MaximumLength = sizeof(WCHAR);
665 if (ReferenceString && ReferenceString->Length)
666 SubKeyName.MaximumLength += ReferenceString->Length;
667 SubKeyName.Buffer = ExAllocatePool(
668 NonPagedPool,
669 SubKeyName.MaximumLength);
670 if (!SubKeyName.Buffer)
671 {
672 DPRINT("ExAllocatePool() failed\n");
673 ZwClose(InterfaceKey);
674 ExFreePool(BaseKeyName.Buffer);
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677 RtlAppendUnicodeToString(&SubKeyName, L"#");
678 if (ReferenceString && ReferenceString->Length)
679 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString);
680
681 /* Create SubKeyName key in registry */
682 InitializeObjectAttributes(
683 &ObjectAttributes,
684 &SubKeyName,
685 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
686 InterfaceKey, /* RootDirectory */
687 NULL); /* SecurityDescriptor */
688
689 Status = ZwCreateKey(
690 &SubKey,
691 KEY_WRITE,
692 &ObjectAttributes,
693 0, /* TileIndex */
694 NULL, /* Class */
695 REG_OPTION_VOLATILE,
696 NULL); /* Disposition */
697
698 if (!NT_SUCCESS(Status))
699 {
700 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
701 ZwClose(InterfaceKey);
702 ExFreePool(BaseKeyName.Buffer);
703 return Status;
704 }
705
706 /* Create symbolic link name: \\?\ACPI#PNP0501#1#{GUID}\ReferenceString */
707 SymbolicLinkName->Length = 0;
708 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length
709 + 4 * sizeof(WCHAR) /* 5 = size of \\??\ */
710 + InstancePath->Length
711 + sizeof(WCHAR) /* 1 = size of # */
712 + GuidString.Length
713 + sizeof(WCHAR); /* final NULL */
714 if (ReferenceString && ReferenceString->Length)
715 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length;
716 SymbolicLinkName->Buffer = ExAllocatePool(
717 NonPagedPool,
718 SymbolicLinkName->MaximumLength);
719 if (!SymbolicLinkName->Buffer)
720 {
721 DPRINT("ExAllocatePool() failed\n");
722 ZwClose(InterfaceKey);
723 ZwClose(SubKey);
724 ExFreePool(SubKeyName.Buffer);
725 ExFreePool(BaseKeyName.Buffer);
726 return STATUS_INSUFFICIENT_RESOURCES;
727 }
728 RtlAppendUnicodeToString(SymbolicLinkName, L"\\\\??\\");
729 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR);
730 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath);
731 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++)
732 {
733 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\')
734 SymbolicLinkName->Buffer[StartIndex + i] = '#';
735 }
736 RtlAppendUnicodeToString(SymbolicLinkName, L"#");
737 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString);
738 if (ReferenceString && ReferenceString->Length)
739 {
740 RtlAppendUnicodeToString(SymbolicLinkName, L"\\");
741 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString);
742 }
743 SymbolicLinkName->Buffer[SymbolicLinkName->Length] = '\0';
744
745 /* Create symbolic link */
746 Status = IoCreateSymbolicLink(SymbolicLinkName, InstancePath);
747 if (!NT_SUCCESS(Status))
748 {
749 DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status);
750 ZwClose(InterfaceKey);
751 ZwClose(SubKey);
752 ExFreePool(SubKeyName.Buffer);
753 ExFreePool(BaseKeyName.Buffer);
754 ExFreePool(SymbolicLinkName->Buffer);
755 return Status;
756 }
757
758 /* Write symbolic link name in registry */
759 Status = ZwSetValueKey(
760 SubKey,
761 &SymbolicLink,
762 0, /* TileIndex */
763 REG_SZ,
764 SymbolicLinkName->Buffer,
765 SymbolicLinkName->Length);
766 if (!NT_SUCCESS(Status))
767 {
768 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
769 ExFreePool(SymbolicLinkName->Buffer);
770 }
771
772 ZwClose(InterfaceKey);
773 ZwClose(SubKey);
774 ExFreePool(SubKeyName.Buffer);
775 ExFreePool(BaseKeyName.Buffer);
776
777 return Status;
778 }
779
780 /*
781 * @unimplemented
782 */
783
784 NTSTATUS STDCALL
785 IoSetDeviceInterfaceState(
786 IN PUNICODE_STRING SymbolicLinkName,
787 IN BOOLEAN Enable)
788 {
789 DPRINT("IoSetDeviceInterfaceState called (UNIMPLEMENTED)\n");
790 return STATUS_SUCCESS;
791 }
792
793 /* EOF */