xref: /reactos/drivers/ksfilter/ks/swenum.c (revision 845faec4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/swenum.c
5  * PURPOSE:         KS Software BUS functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #include <stdio.h>
12 #include <swenum.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 LONG KsDeviceCount = 0;
18 
19 typedef NTSTATUS (NTAPI *PKSP_BUS_ENUM_CALLBACK)(
20     IN PHANDLE hKey,
21     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
22     IN PBUS_DEVICE_ENTRY DummyEntry,
23     IN LPWSTR RootName,
24     IN LPWSTR DirectoryName);
25 
26 NTSTATUS
27 KspCreatePDO(
28     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
29     IN PBUS_DEVICE_ENTRY DeviceEntry,
30     OUT PDEVICE_OBJECT * OutDeviceObject)
31 {
32     PDEVICE_OBJECT DeviceObject;
33     WCHAR Buffer[50];
34     ULONG CurDeviceId;
35     UNICODE_STRING DeviceName;
36     NTSTATUS Status;
37     PCOMMON_DEVICE_EXTENSION DeviceExtension;
38 
39     /* increment device count */
40     CurDeviceId = InterlockedIncrement(&KsDeviceCount);
41 
42     /* generate new device id */
43     swprintf(Buffer, L"\\Device\\KSENUM%08x", CurDeviceId);
44 
45     /* initialize new device name */
46     RtlInitUnicodeString(&DeviceName, Buffer);
47 
48     /* create new device object */
49     Status = IoCreateDevice(BusDeviceExtension->BusDeviceObject->DriverObject, sizeof(PVOID), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);
50 
51     /* check for success */
52     if (!NT_SUCCESS(Status))
53     {
54         /* failed to create pdo */
55         return Status;
56     }
57 
58     /* now allocate device extension */
59     DeviceExtension = (PCOMMON_DEVICE_EXTENSION)AllocateItem(NonPagedPool, sizeof(COMMON_DEVICE_EXTENSION));
60     if (!DeviceExtension)
61     {
62         /* no memory */
63         IoDeleteDevice(DeviceObject);
64         return STATUS_INSUFFICIENT_RESOURCES;
65     }
66 
67     /* store device extension */
68     *((PVOID*)DeviceObject->DeviceExtension) = DeviceExtension;
69 
70     /* initialize device extension */
71     DeviceExtension->IsBus = FALSE;
72     DeviceExtension->DeviceObject = DeviceObject;
73     DeviceExtension->DeviceEntry = DeviceEntry;
74     DeviceExtension->BusDeviceExtension = BusDeviceExtension;
75 
76     /* not started yet*/
77     DeviceEntry->DeviceState = NotStarted;
78 
79     /* get current time */
80     KeQuerySystemTime(&DeviceEntry->TimeCreated);
81 
82     /* setup flags */
83     DeviceObject->Flags |= DO_POWER_PAGABLE;
84     DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
85     /* TODO: fire time when expired */
86 
87     *OutDeviceObject = DeviceObject;
88 
89     return STATUS_SUCCESS;
90 }
91 
92 NTSTATUS
93 KspRegisterDeviceAssociation(
94     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
95     IN PBUS_DEVICE_ENTRY DeviceEntry,
96     IN OUT PBUS_INSTANCE_ENTRY BusInstanceEntry)
97 {
98     NTSTATUS Status;
99     UNICODE_STRING ReferenceString;
100 
101     /* initialize reference string */
102     RtlInitUnicodeString(&ReferenceString, DeviceEntry->DeviceName);
103 
104     /* register device interface */
105     Status = IoRegisterDeviceInterface(BusDeviceExtension->PhysicalDeviceObject, &BusInstanceEntry->InterfaceGuid, &ReferenceString, &BusInstanceEntry->SymbolicLink);
106 
107     /* check for success */
108     if (!NT_SUCCESS(Status))
109     {
110         /* failed */
111         return Status;
112     }
113 
114     /* now enable the interface */
115     Status = IoSetDeviceInterfaceState(&BusInstanceEntry->SymbolicLink, TRUE);
116 
117     /* check for success */
118     if (!NT_SUCCESS(Status))
119     {
120         /* failed, free memory */
121         FreeItem(BusInstanceEntry->SymbolicLink.Buffer);
122         return Status;
123     }
124 
125     DPRINT("Registered DeviceInterface %wZ\n", &BusInstanceEntry->SymbolicLink);
126 
127 
128     /* done */
129     return Status;
130 }
131 
132 VOID
133 KspRemoveDeviceAssociations(
134     IN PBUS_DEVICE_ENTRY DeviceEntry)
135 {
136     PLIST_ENTRY Entry;
137     PBUS_INSTANCE_ENTRY CurEntry;
138 
139     /* remove all entries */
140     Entry = DeviceEntry->DeviceInterfaceList.Flink;
141 
142     while(Entry != &DeviceEntry->DeviceInterfaceList)
143     {
144          /* get offset */
145          CurEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
146 
147          /* sanity check */
148          ASSERT(CurEntry->SymbolicLink.Buffer);
149 
150          /* de-register interface */
151          IoSetDeviceInterfaceState(&CurEntry->SymbolicLink, FALSE);
152 
153          /* free symbolic link buffer */
154          FreeItem(CurEntry->SymbolicLink.Buffer);
155 
156          /* remove entry from list */
157          RemoveEntryList(Entry);
158 
159          /* move to next entry */
160          Entry = Entry->Flink;
161 
162          /* free entry */
163          FreeItem(CurEntry);
164     }
165 }
166 
167 NTSTATUS
168 KspEnumerateBusRegistryKeys(
169     IN HANDLE hKey,
170     IN LPWSTR ReferenceString,
171     IN PKSP_BUS_ENUM_CALLBACK Callback,
172     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
173     IN PBUS_DEVICE_ENTRY DeviceEntry)
174 {
175     UNICODE_STRING String;
176     OBJECT_ATTRIBUTES ObjectAttributes;
177     HANDLE hNewKey;
178     NTSTATUS Status;
179     ULONG ResultLength, Index, KeyInfoLength;
180     KEY_FULL_INFORMATION KeyInformation;
181     PKEY_BASIC_INFORMATION KeyInfo;
182 
183     /* initialize key name */
184     RtlInitUnicodeString(&String, ReferenceString);
185 
186     /* initialize object attributes */
187     InitializeObjectAttributes(&ObjectAttributes, &String, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hKey, NULL);
188 
189     /* open new key */
190     Status = ZwOpenKey(&hNewKey, GENERIC_READ, &ObjectAttributes);
191 
192     /* check for success */
193     if (!NT_SUCCESS(Status))
194     {
195         /* failed to open key */
196 
197         return Status;
198     }
199 
200     /* query key stats */
201     Status = ZwQueryKey(hNewKey, KeyFullInformation, &KeyInformation, sizeof(KeyInformation), &ResultLength);
202 
203     if (!NT_SUCCESS(Status))
204     {
205         /* close key */
206         ZwClose(hNewKey);
207 
208         /* done */
209         return Status;
210     }
211 
212     /* calculate key info length */
213     KeyInfoLength = KeyInformation.MaxNameLen + sizeof(KEY_BASIC_INFORMATION) + 1 * sizeof(WCHAR);
214 
215     /* allocate buffer */
216     KeyInfo = (PKEY_BASIC_INFORMATION)AllocateItem(NonPagedPool, KeyInfoLength);
217     if (!KeyInfo)
218     {
219 
220         /* no memory */
221         ZwClose(hNewKey);
222 
223         /* done */
224         return STATUS_INSUFFICIENT_RESOURCES;
225     }
226 
227     /* enumerate all keys */
228     for(Index = 0; Index < KeyInformation.SubKeys; Index++)
229     {
230 
231         /* query sub key */
232         Status = ZwEnumerateKey(hNewKey, Index, KeyBasicInformation, (PVOID)KeyInfo, KeyInfoLength, &ResultLength);
233 
234         /* check for success */
235         if (NT_SUCCESS(Status))
236         {
237             /* perform callback */
238             Status = Callback(hNewKey, BusDeviceExtension, DeviceEntry, KeyInfo->Name, ReferenceString);
239 
240             /* should enumeration stop */
241             if (!NT_SUCCESS(Status))
242                 break;
243         }
244     }
245 
246     /* free info buffer */
247     FreeItem(KeyInfo);
248 
249     /* close key */
250     ZwClose(hNewKey);
251 
252     /* done */
253     return Status;
254 }
255 
256 NTSTATUS
257 NTAPI
258 KspCreateDeviceAssociation(
259     IN PHANDLE hKey,
260     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
261     IN PBUS_DEVICE_ENTRY DeviceEntry,
262     IN LPWSTR InterfaceString,
263     IN LPWSTR ReferenceString)
264 {
265     GUID InterfaceGUID;
266     NTSTATUS Status;
267     PLIST_ENTRY Entry;
268     PBUS_INSTANCE_ENTRY CurEntry;
269     UNICODE_STRING DeviceName;
270 
271     /* initialize interface string */
272     RtlInitUnicodeString(&DeviceName, InterfaceString);
273 
274     /* first convert device name to guid */
275     RtlGUIDFromString(&DeviceName, &InterfaceGUID);
276 
277     /* check if the device is already present */
278     Entry = DeviceEntry->DeviceInterfaceList.Flink;
279     DPRINT("KspCreateDeviceAssociation ReferenceString %S\n", ReferenceString);
280     DPRINT("KspCreateDeviceAssociation InterfaceString %S\n", InterfaceString);
281 
282     while(Entry != &DeviceEntry->DeviceInterfaceList)
283     {
284          /* get offset */
285          CurEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
286 
287          if (IsEqualGUIDAligned(&CurEntry->InterfaceGuid, &InterfaceGUID))
288          {
289              /* entry already exists */
290              return STATUS_SUCCESS;
291          }
292 
293          /* move to next entry */
294          Entry = Entry->Flink;
295     }
296 
297     /* time to allocate new entry */
298     CurEntry = (PBUS_INSTANCE_ENTRY)AllocateItem(NonPagedPool, sizeof(BUS_INSTANCE_ENTRY));
299 
300     if (!CurEntry)
301     {
302         /* no memory */
303         return STATUS_INSUFFICIENT_RESOURCES;
304     }
305 
306     /* store guid */
307     RtlMoveMemory(&CurEntry->InterfaceGuid, &InterfaceGUID, sizeof(GUID));
308 
309     /* now register the association */
310     Status = KspRegisterDeviceAssociation(BusDeviceExtension, DeviceEntry, CurEntry);
311 
312     /* check for success */
313     if (NT_SUCCESS(Status))
314     {
315         /* store entry */
316         InsertTailList(&DeviceEntry->DeviceInterfaceList, &CurEntry->Entry);
317     }
318     else
319     {
320         /* failed to associated device */
321         FreeItem(CurEntry);
322     }
323 
324      /* done */
325      return Status;
326 }
327 
328 NTSTATUS
329 NTAPI
330 KspCreateDeviceReference(
331     IN PHANDLE hKey,
332     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
333     IN PBUS_DEVICE_ENTRY DummyEntry,
334     IN LPWSTR InterfaceId,
335     IN LPWSTR DeviceId)
336 {
337     LPWSTR DeviceName;
338     SIZE_T Length;
339     PLIST_ENTRY Entry;
340     PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* GCC warning */
341     BOOLEAN ItemExists = FALSE;
342     UNICODE_STRING String;
343     NTSTATUS Status;
344     KIRQL OldLevel;
345 
346     /* first construct device name & reference guid */
347     Length = wcslen(DeviceId) + wcslen(InterfaceId);
348 
349     /* append '&' and null byte */
350     Length += 2;
351 
352     /* allocate device name */
353     DeviceName = AllocateItem(NonPagedPool, Length * sizeof(WCHAR));
354 
355     if (!DeviceName)
356     {
357         /* not enough memory */
358         return STATUS_INSUFFICIENT_RESOURCES;
359     }
360 
361     /* construct device name */
362     wcscpy(DeviceName, DeviceId);
363     wcscat(DeviceName, L"&");
364     wcscat(DeviceName, InterfaceId);
365 
366     /* scan list and check if it is already present */
367     Entry = BusDeviceExtension->Common.Entry.Flink;
368 
369     while(Entry != &BusDeviceExtension->Common.Entry)
370     {
371         /* get real offset */
372         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
373 
374         /* check if name matches */
375         if (!wcsicmp(DeviceEntry->DeviceName, DeviceName))
376         {
377             /* item already exists */
378             ItemExists = TRUE;
379             break;
380         }
381 
382         /* move to next entry */
383         Entry = Entry->Flink;
384     }
385 
386     if (!ItemExists)
387     {
388         /* allocate new device entry */
389         DeviceEntry = AllocateItem(NonPagedPool, sizeof(BUS_DEVICE_ENTRY));
390         if (!DeviceEntry)
391         {
392             /* no memory */
393             FreeItem(DeviceName);
394             return STATUS_INSUFFICIENT_RESOURCES;
395         }
396 
397         /* initialize device entry */
398         InitializeListHead(&DeviceEntry->DeviceInterfaceList);
399         InitializeListHead(&DeviceEntry->IrpPendingList);
400 
401         /* copy device guid */
402         RtlInitUnicodeString(&String, DeviceId);
403         RtlGUIDFromString(&String, &DeviceEntry->DeviceGuid);
404 
405         /* copy device names */
406         DeviceEntry->DeviceName = DeviceName;
407         DeviceEntry->Instance = (DeviceName + wcslen(DeviceId) + 1);
408 
409         /* copy name */
410         DeviceEntry->BusId = AllocateItem(NonPagedPool, (wcslen(DeviceId) + 1) * sizeof(WCHAR));
411         if (!DeviceEntry->BusId)
412         {
413             /* no memory */
414             FreeItem(DeviceName);
415             FreeItem(DeviceEntry);
416             return STATUS_INSUFFICIENT_RESOURCES;
417         }
418         wcscpy(DeviceEntry->BusId, DeviceId);
419     }
420 
421     /* now enumerate the interfaces */
422     Status = KspEnumerateBusRegistryKeys(hKey, InterfaceId, KspCreateDeviceAssociation, BusDeviceExtension, DeviceEntry);
423 
424     /* check if list is empty */
425     if (IsListEmpty(&DeviceEntry->DeviceInterfaceList))
426     {
427         /* invalid device settings */
428         FreeItem(DeviceEntry->BusId);
429         FreeItem(DeviceEntry->DeviceName);
430         FreeItem(DeviceEntry);
431 
432         ASSERT(ItemExists == FALSE);
433 
434         return STATUS_INVALID_DEVICE_STATE;
435     }
436 
437     /* check if enumeration failed */
438     if (!NT_SUCCESS(Status))
439     {
440         /* failed */
441         KspRemoveDeviceAssociations(DeviceEntry);
442         FreeItem(DeviceEntry->BusId);
443         FreeItem(DeviceEntry->DeviceName);
444         FreeItem(DeviceEntry);
445 
446         ASSERT(ItemExists == FALSE);
447 
448         /* done */
449         return Status;
450     }
451 
452     if (!ItemExists)
453     {
454         /* acquire lock */
455         KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
456 
457         /* successfully initialized entry */
458         InsertTailList(&BusDeviceExtension->Common.Entry, &DeviceEntry->Entry);
459 
460         /* release lock */
461         KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
462     }
463 
464     /* done */
465     return Status;
466 }
467 
468 NTSTATUS
469 NTAPI
470 KspCreateDeviceReferenceTrampoline(
471     IN PHANDLE hKey,
472     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
473     IN PBUS_DEVICE_ENTRY DummyEntry,
474     IN LPWSTR DeviceCategory,
475     IN LPWSTR ReferenceString)
476 {
477     return KspEnumerateBusRegistryKeys(hKey, DeviceCategory, KspCreateDeviceReference, BusDeviceExtension, DummyEntry);
478 }
479 
480 
481 NTSTATUS
482 KspOpenBusRegistryKey(
483     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
484     OUT PHANDLE hKey)
485 {
486     OBJECT_ATTRIBUTES ObjectAttributes;
487 
488     /* initialize object attributes */
489     InitializeObjectAttributes(&ObjectAttributes, &BusDeviceExtension->ServicePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
490 
491     return ZwCreateKey(hKey, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
492 }
493 
494 NTSTATUS
495 KspScanBus(
496     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension)
497 {
498     HANDLE hKey;
499     NTSTATUS Status;
500 
501     /* first open key */
502     Status = KspOpenBusRegistryKey(BusDeviceExtension, &hKey);
503 
504     /* check for success */
505     if (!NT_SUCCESS(Status))
506     {
507         /* no success */
508 
509         return Status;
510     }
511 
512     /* TODO clear reference marks */
513 
514     /* construct device entries */
515     Status = KspEnumerateBusRegistryKeys(hKey, NULL, KspCreateDeviceReferenceTrampoline, BusDeviceExtension, NULL);
516 
517     /* TODO: delete unreferenced devices */
518 
519     /* close handle */
520     ZwClose(hKey);
521 
522     /* done */
523     return Status;
524 }
525 
526 
527 NTSTATUS
528 NTAPI
529 KspBusQueryReferenceString(
530     IN PVOID Context,
531     IN OUT PWCHAR *String)
532 {
533     LPWSTR Name;
534     SIZE_T Length;
535     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)Context;
536 
537     /* sanity checks */
538     ASSERT(BusDeviceExtension);
539     ASSERT(BusDeviceExtension->BusIdentifier);
540 
541     /* calculate length */
542     Length = wcslen(BusDeviceExtension->BusIdentifier) + 1;
543 
544     /* allocate buffer */
545     Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
546 
547     if (!Name)
548     {
549         /* failed to allocate buffer */
550         return STATUS_INSUFFICIENT_RESOURCES;
551     }
552 
553     /* copy buffer */
554     wcscpy(Name, BusDeviceExtension->BusIdentifier);
555 
556     /* store result */
557     *String = Name;
558 
559     /* done */
560     return STATUS_SUCCESS;
561 }
562 
563 VOID
564 NTAPI
565 KspBusDeviceReference(
566     IN PVOID Context)
567 {
568     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
569 
570     /* reference count */
571     InterlockedIncrement((PLONG)&ChildDeviceExtension->DeviceReferenceCount);
572 }
573 
574 VOID
575 NTAPI
576 KspBusDeviceDereference(
577     IN PVOID Context)
578 {
579     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
580 
581     /* reference count */
582     InterlockedDecrement((PLONG)&ChildDeviceExtension->DeviceReferenceCount);
583 }
584 
585 VOID
586 NTAPI
587 KspBusReferenceDeviceObject(
588     IN PVOID Context)
589 {
590     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
591 
592     /* reference count */
593     InterlockedIncrement((PLONG)&ChildDeviceExtension->DeviceObjectReferenceCount);
594 }
595 
596 VOID
597 NTAPI
598 KspBusDereferenceDeviceObject(
599     IN PVOID Context)
600 {
601     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
602 
603     /* reference count */
604     InterlockedDecrement((PLONG)&ChildDeviceExtension->DeviceObjectReferenceCount);
605 }
606 
607 NTSTATUS
608 KspQueryBusDeviceInterface(
609     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
610     IN PIRP Irp)
611 {
612     PBUS_INTERFACE_SWENUM Interface;
613     PIO_STACK_LOCATION IoStack;
614 
615     /* get current irp stack location */
616     IoStack = IoGetCurrentIrpStackLocation(Irp);
617 
618     /* sanity checks */
619     ASSERT(IoStack->Parameters.QueryInterface.Size == sizeof(BUS_INTERFACE_SWENUM));
620     ASSERT(IoStack->Parameters.QueryInterface.Interface);
621 
622     /* fill in interface */
623     Interface = (PBUS_INTERFACE_SWENUM)IoStack->Parameters.QueryInterface.Interface;
624     Interface->Interface.Size = sizeof(BUS_INTERFACE_SWENUM);
625     Interface->Interface.Version = BUS_INTERFACE_SWENUM_VERSION;
626     Interface->Interface.Context = ChildDeviceExtension;
627     Interface->Interface.InterfaceReference = KspBusDeviceReference;
628     Interface->Interface.InterfaceDereference = KspBusDeviceDereference;
629     Interface->ReferenceDeviceObject = KspBusReferenceDeviceObject;
630     Interface->DereferenceDeviceObject = KspBusDereferenceDeviceObject;
631     Interface->QueryReferenceString = KspBusQueryReferenceString;
632 
633     return STATUS_SUCCESS;
634 }
635 
636 NTSTATUS
637 KspEnableBusDeviceInterface(
638     PBUS_DEVICE_ENTRY DeviceEntry,
639     BOOLEAN bEnable)
640 {
641     PLIST_ENTRY Entry;
642     PBUS_INSTANCE_ENTRY InstanceEntry;
643     NTSTATUS Status = STATUS_SUCCESS;
644 
645     /* enable now all interfaces */
646     Entry = DeviceEntry->DeviceInterfaceList.Flink;
647 
648     while(Entry != &DeviceEntry->DeviceInterfaceList)
649     {
650         /* get bus instance entry */
651         InstanceEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
652         DPRINT("Enabling %u %wZ Irql %u\n", bEnable, &InstanceEntry->SymbolicLink, KeGetCurrentIrql());
653 
654         /* set interface state */
655         Status = IoSetDeviceInterfaceState(&InstanceEntry->SymbolicLink, bEnable);
656 
657         if (!NT_SUCCESS(Status))
658         {
659             /* failed to set interface */
660             break;
661         }
662 
663         /* move to next entry */
664         Entry = Entry->Flink;
665     }
666 
667     /* done */
668     return Status;
669 }
670 
671 NTSTATUS
672 KspDoReparseForIrp(
673     PIRP Irp,
674     PBUS_DEVICE_ENTRY DeviceEntry)
675 {
676     SIZE_T Length;
677     LPWSTR Buffer;
678     PIO_STACK_LOCATION IoStack;
679 
680     /* get stack location */
681     IoStack = IoGetCurrentIrpStackLocation(Irp);
682 
683     /* sanity checks */
684     ASSERT(DeviceEntry->PDODeviceName);
685     ASSERT(DeviceEntry->Instance);
686     ASSERT(IoStack->FileObject);
687     ASSERT(IoStack->FileObject->FileName.Buffer);
688 
689     /* calculate length */
690     Length = wcslen(DeviceEntry->PDODeviceName);
691     Length += wcslen(DeviceEntry->Instance);
692 
693     /* zero byte and '\\' */
694     Length += 2;
695 
696     /* allocate buffer */
697     Buffer = ExAllocatePoolWithTag(NonPagedPool, Length * sizeof(WCHAR), 'mNoI');
698     if (!Buffer)
699     {
700         /* no resources */
701         return STATUS_INSUFFICIENT_RESOURCES;
702     }
703 
704     /* construct buffer */
705     swprintf(Buffer, L"%s\\%s", DeviceEntry->PDODeviceName, DeviceEntry->Instance);
706 
707     /* free old buffer*/
708     ExFreePoolWithTag(IoStack->FileObject->FileName.Buffer, 'mNoI');
709 
710     /* store new file name */
711     RtlInitUnicodeString(&IoStack->FileObject->FileName, Buffer);
712 
713     /* done */
714     return STATUS_REPARSE;
715 }
716 
717 VOID
718 KspCompletePendingIrps(
719     IN PBUS_DEVICE_ENTRY DeviceEntry,
720     IN OUT NTSTATUS ResultCode)
721 {
722     PLIST_ENTRY Entry;
723     PIRP Irp;
724     NTSTATUS Status;
725 
726     /* go through list */
727     while(!IsListEmpty(&DeviceEntry->IrpPendingList))
728     {
729         /* get first entry */
730         Entry = RemoveHeadList(&DeviceEntry->IrpPendingList);
731 
732         /* get irp */
733         Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
734 
735         if (ResultCode == STATUS_REPARSE)
736         {
737             /* construct reparse information */
738             Status = KspDoReparseForIrp(Irp, DeviceEntry);
739         }
740         else
741         {
742             /* use default code */
743             Status = ResultCode;
744         }
745 
746         /* store result code */
747         Irp->IoStatus.Status = Status;
748 
749         DPRINT("Completing IRP %p Status %x\n", Irp, Status);
750 
751         /* complete the request */
752         CompleteRequest(Irp, IO_NO_INCREMENT);
753     }
754 
755 }
756 
757 
758 
759 NTSTATUS
760 KspStartBusDevice(
761     IN PDEVICE_OBJECT DeviceObject,
762     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
763     IN PIRP Irp)
764 {
765     WCHAR PDOName[256];
766     NTSTATUS Status;
767     ULONG ResultLength;
768     LPWSTR Name;
769     ULONG NameLength;
770     PBUS_DEVICE_ENTRY DeviceEntry;
771 
772     /* FIXME handle pending remove */
773 
774     /* get full device name */
775     Status = IoGetDeviceProperty(DeviceObject, DevicePropertyPhysicalDeviceObjectName, sizeof(PDOName), PDOName, &ResultLength);
776 
777     if (!NT_SUCCESS(Status))
778     {
779         /* failed to get device name */
780         return Status;
781     }
782 
783     /* allocate device name buffer */
784     NameLength = ResultLength + sizeof(UNICODE_NULL);
785     Name = AllocateItem(NonPagedPool, NameLength);
786     if (!Name)
787     {
788         /* no memory */
789         return STATUS_INSUFFICIENT_RESOURCES;
790     }
791 
792     /* copy name */
793     NT_VERIFY(NT_SUCCESS(RtlStringCbCopyW(Name, NameLength, PDOName)));
794 
795     /* TODO: time stamp creation time */
796 
797     /* get device entry */
798     DeviceEntry = (PBUS_DEVICE_ENTRY)ChildDeviceExtension->DeviceEntry;
799 
800     /* sanity check */
801     ASSERT(DeviceEntry);
802 
803     /* store device name */
804     DeviceEntry->PDODeviceName = Name;
805 
806     /* mark device as started */
807     DeviceEntry->DeviceState = Started;
808 
809     /* reference start time */
810     KeQuerySystemTime(&DeviceEntry->TimeCreated);
811 
812     DPRINT1("KspStartBusDevice Name %S DeviceName %S Instance %S Started\n", Name, DeviceEntry->DeviceName, DeviceEntry->Instance);
813 
814     /* enable device classes */
815     //KspEnableBusDeviceInterface(DeviceEntry, TRUE);
816 
817     /* done */
818     return STATUS_SUCCESS;
819 }
820 
821 NTSTATUS
822 KspQueryBusDeviceCapabilities(
823     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
824     IN PIRP Irp)
825 {
826     PDEVICE_CAPABILITIES Capabilities;
827     PIO_STACK_LOCATION IoStack;
828 
829     /* get stack location */
830     IoStack = IoGetCurrentIrpStackLocation(Irp);
831 
832     /* get capabilities */
833     Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
834 
835     RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
836 
837     /* setup capabilities */
838     Capabilities->UniqueID = TRUE;
839     Capabilities->SilentInstall = TRUE;
840     Capabilities->SurpriseRemovalOK = TRUE;
841     Capabilities->Address = 0;
842     Capabilities->UINumber = 0;
843     Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
844     Capabilities->DeviceWake = PowerDeviceD0;
845 
846     /* done */
847     return STATUS_SUCCESS;
848 }
849 
850 NTSTATUS
851 KspQueryBusInformation(
852     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
853     IN PIRP Irp)
854 {
855     PPNP_BUS_INFORMATION BusInformation;
856 
857     /* allocate bus information */
858     BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
859 
860     if (!BusInformation)
861     {
862         /* no memory */
863         return STATUS_INSUFFICIENT_RESOURCES;
864     }
865 
866     /* return info */
867     BusInformation->BusNumber = 0;
868     BusInformation->LegacyBusType = InterfaceTypeUndefined;
869     RtlMoveMemory(&BusInformation->BusTypeGuid, &KSMEDIUMSETID_Standard, sizeof(GUID));
870 
871     /* store result */
872     Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
873 
874     /* done */
875     return STATUS_SUCCESS;
876 }
877 
878 NTSTATUS
879 KspQueryBusDevicePnpState(
880     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
881     IN PIRP Irp)
882 {
883     /* set device flags */
884     Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
885 
886     /* done */
887     return STATUS_SUCCESS;
888 }
889 
890 NTSTATUS
891 KspQueryId(
892     IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
893     IN PIRP Irp)
894 {
895     PIO_STACK_LOCATION IoStack;
896     PBUS_DEVICE_ENTRY DeviceEntry;
897     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
898     LPWSTR Name;
899     SIZE_T Length;
900 
901     /* get current irp stack location */
902     IoStack = IoGetCurrentIrpStackLocation(Irp);
903 
904     if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
905     {
906         /* get device entry */
907         DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
908 
909         /* sanity check */
910         ASSERT(DeviceEntry);
911         ASSERT(DeviceEntry->Instance);
912 
913         /* calculate length */
914         Length = wcslen(DeviceEntry->Instance) + 2;
915 
916         /* allocate buffer */
917         Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
918 
919         if (!Name)
920         {
921             /* failed to allocate buffer */
922             return STATUS_INSUFFICIENT_RESOURCES;
923         }
924 
925         /* copy buffer */
926         wcscpy(Name, DeviceEntry->Instance);
927 
928         /* store result */
929         Irp->IoStatus.Information = (ULONG_PTR)Name;
930 
931         /* done */
932         return STATUS_SUCCESS;
933     }
934     else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
935              IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
936     {
937         /* get device entry */
938         DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
939 
940         /* get bus device extension */
941         BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION) ChildDeviceExtension->BusDeviceExtension;
942 
943         /* sanity check */
944         ASSERT(DeviceEntry);
945         ASSERT(DeviceEntry->BusId);
946         ASSERT(BusDeviceExtension);
947         ASSERT(BusDeviceExtension->BusIdentifier);
948 
949         /* calculate length */
950         Length = wcslen(BusDeviceExtension->BusIdentifier);
951         Length += wcslen(DeviceEntry->BusId);
952 
953         /* extra length for '\\' and 2 zero bytes */
954         Length += 4;
955 
956         /* allocate buffer */
957         Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
958         if (!Name)
959         {
960             /* failed to allocate buffer */
961             return STATUS_INSUFFICIENT_RESOURCES;
962         }
963 
964         /* construct id */
965         wcscpy(Name, BusDeviceExtension->BusIdentifier);
966         wcscat(Name, L"\\");
967         wcscat(Name, DeviceEntry->BusId);
968         //swprintf(Name, L"%s\\%s", BusDeviceExtension->BusIdentifier, DeviceEntry->BusId);
969 
970         /* store result */
971         Irp->IoStatus.Information = (ULONG_PTR)Name;
972 
973         /* done */
974         return STATUS_SUCCESS;
975     }
976     else
977     {
978         /* other ids are not supported */
979         //DPRINT1("Not Supported ID Type %x\n", IoStack->Parameters.QueryId.IdType);
980         return Irp->IoStatus.Status;
981     }
982 }
983 
984 NTSTATUS
985 KspInstallInterface(
986     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
987     IN PSWENUM_INSTALL_INTERFACE InstallInterface)
988 {
989     SIZE_T Length, Index;
990     UNICODE_STRING DeviceString, InterfaceString, ReferenceString;
991     HANDLE hKey, hDeviceKey, hInterfaceKey, hReferenceKey;
992     NTSTATUS Status;
993     OBJECT_ATTRIBUTES ObjectAttributes;
994 
995     /* sanity check */
996     ASSERT(InstallInterface);
997 
998     /* calculate length */
999     Length = wcslen(InstallInterface->ReferenceString);
1000 
1001     /* check for invalid characters */
1002     for(Index = 0; Index < Length; Index++)
1003     {
1004         if (InstallInterface->ReferenceString[Index] <= L' ' ||
1005             InstallInterface->ReferenceString[Index] > L'~' ||
1006             InstallInterface->ReferenceString[Index] == L',' ||
1007             InstallInterface->ReferenceString[Index] == L'\\' ||
1008             InstallInterface->ReferenceString[Index] == L'/')
1009         {
1010             /* invalid character */
1011             return STATUS_INVALID_PARAMETER;
1012         }
1013     }
1014 
1015     /* open bus key */
1016     Status = KspOpenBusRegistryKey(BusDeviceExtension, &hKey);
1017     if (NT_SUCCESS(Status))
1018     {
1019         /* convert device guid to string */
1020         Status = RtlStringFromGUID(&InstallInterface->DeviceId, &DeviceString);
1021         if (NT_SUCCESS(Status))
1022         {
1023             /* initialize object attributes */
1024             InitializeObjectAttributes(&ObjectAttributes, &DeviceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hKey, NULL);
1025 
1026             /* construct device key */
1027             Status = ZwCreateKey(&hDeviceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1028             if (NT_SUCCESS(Status))
1029             {
1030                 /* convert interface guid to string */
1031                 Status = RtlStringFromGUID(&InstallInterface->InterfaceId, &InterfaceString);
1032                 if (NT_SUCCESS(Status))
1033                 {
1034                     /* initialize object attributes */
1035                     InitializeObjectAttributes(&ObjectAttributes, &InterfaceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceKey, NULL);
1036 
1037                     /* construct device key */
1038                     Status = ZwCreateKey(&hInterfaceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1039                     if (NT_SUCCESS(Status))
1040                     {
1041                         /* initialize reference string */
1042                         RtlInitUnicodeString(&ReferenceString, InstallInterface->ReferenceString);
1043 
1044                         /* initialize object attributes */
1045                         InitializeObjectAttributes(&ObjectAttributes, &ReferenceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hInterfaceKey, NULL);
1046 
1047                         /* construct device key */
1048                         Status = ZwCreateKey(&hReferenceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1049                         if (NT_SUCCESS(Status))
1050                         {
1051                             /* close key */
1052                             ZwClose(hReferenceKey);
1053                         }
1054                     }
1055                     /* free interface string */
1056                     RtlFreeUnicodeString(&InterfaceString);
1057 
1058                     /* close reference key */
1059                     ZwClose(hInterfaceKey);
1060                 }
1061                 /* close device key */
1062                 ZwClose(hDeviceKey);
1063             }
1064             /* free device string */
1065             RtlFreeUnicodeString(&DeviceString);
1066         }
1067         /* close bus key */
1068         ZwClose(hKey);
1069     }
1070 
1071     /* done */
1072     return Status;
1073  }
1074 
1075 VOID
1076 NTAPI
1077 KspInstallBusEnumInterface(
1078     IN PVOID Ctx)
1079 {
1080     PIO_STACK_LOCATION IoStack;
1081     NTSTATUS Status;
1082     PLIST_ENTRY Entry;
1083     PBUS_DEVICE_ENTRY DeviceEntry;
1084     PSWENUM_INSTALL_INTERFACE InstallInterface;
1085     KIRQL OldLevel;
1086     PBUS_INSTALL_ENUM_CONTEXT Context = (PBUS_INSTALL_ENUM_CONTEXT)Ctx;
1087 
1088     /* get current irp stack location */
1089     IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
1090 
1091     /* get install request */
1092     InstallInterface = (PSWENUM_INSTALL_INTERFACE)Context->Irp->AssociatedIrp.SystemBuffer;
1093 
1094     /* sanity check */
1095     ASSERT(InstallInterface);
1096     ASSERT(Context->BusDeviceExtension);
1097 
1098     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SWENUM_INSTALL_INTERFACE))
1099     {
1100         /* buffer too small */
1101         Context->Status = STATUS_INVALID_PARAMETER;
1102 
1103         /* signal completion */
1104         KeSetEvent(&Context->Event, 0, FALSE);
1105 
1106         /* done */
1107         return;
1108     }
1109 
1110     /* FIXME locks */
1111 
1112     /* now install the interface */
1113     Status = KspInstallInterface(Context->BusDeviceExtension, InstallInterface);
1114     if (!NT_SUCCESS(Status))
1115     {
1116         /* failed to install interface */
1117         Context->Status = Status;
1118 
1119         /* signal completion */
1120         KeSetEvent(&Context->Event, 0, FALSE);
1121 
1122         /* done */
1123         return;
1124     }
1125 
1126     /* now scan the bus */
1127     Status = KspScanBus(Context->BusDeviceExtension);
1128     // FIXME: We may need to check for success here, and properly fail...
1129     ASSERT(NT_SUCCESS(Status));
1130 
1131     /* acquire device entry lock */
1132     KeAcquireSpinLock(&Context->BusDeviceExtension->Lock, &OldLevel);
1133 
1134     /* now iterate all device entries */
1135     ASSERT(!IsListEmpty(&Context->BusDeviceExtension->Common.Entry));
1136     Entry = Context->BusDeviceExtension->Common.Entry.Flink;
1137     while(Entry != &Context->BusDeviceExtension->Common.Entry)
1138     {
1139         /* get device entry */
1140         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1141         if (IsEqualGUIDAligned(&DeviceEntry->DeviceGuid, &InstallInterface->DeviceId))
1142         {
1143             if (!DeviceEntry->PDO)
1144             {
1145                 /* release device entry lock */
1146                 KeReleaseSpinLock(&Context->BusDeviceExtension->Lock, OldLevel);
1147 
1148                 /* create pdo */
1149                 Status = KspCreatePDO(Context->BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1150 
1151                 /* acquire device entry lock */
1152                 KeAcquireSpinLock(&Context->BusDeviceExtension->Lock, &OldLevel);
1153 
1154                 /* done */
1155                 break;
1156             }
1157         }
1158 
1159         /* move to next entry */
1160         Entry = Entry->Flink;
1161     }
1162 
1163     /* release device entry lock */
1164     KeReleaseSpinLock(&Context->BusDeviceExtension->Lock, OldLevel);
1165 
1166     /* signal that bus driver relations has changed */
1167     IoInvalidateDeviceRelations(Context->BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1168 
1169     /* update status */
1170     Context->Status = Status;
1171 
1172     /* signal completion */
1173     KeSetEvent(&Context->Event, 0, FALSE);
1174 }
1175 
1176 
1177 VOID
1178 NTAPI
1179 KspBusWorkerRoutine(
1180   IN PVOID Parameter)
1181 {
1182     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1183     PBUS_DEVICE_ENTRY DeviceEntry;
1184     PLIST_ENTRY Entry;
1185     LARGE_INTEGER Time, Diff;
1186     BOOLEAN DoInvalidate = FALSE;
1187     KIRQL OldLevel;
1188 
1189     /* get device extension */
1190     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)Parameter;
1191 
1192     /* acquire lock */
1193     KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1194 
1195     /* get current time */
1196     KeQuerySystemTime(&Time);
1197 
1198     /* enumerate all device entries */
1199     Entry = BusDeviceExtension->Common.Entry.Flink;
1200     while(Entry != &BusDeviceExtension->Common.Entry)
1201     {
1202         /* get offset to device entry */
1203         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1204 
1205         /* sanity check */
1206         ASSERT(DeviceEntry);
1207 
1208         //DPRINT1("DeviceEntry %p PDO %p State %x\n", DeviceEntry, DeviceEntry->PDO, DeviceEntry->DeviceState);
1209 
1210         if (DeviceEntry->PDO)
1211         {
1212             if (DeviceEntry->DeviceState == NotStarted)
1213             {
1214                 Diff.QuadPart = Time.QuadPart - DeviceEntry->TimeCreated.QuadPart;
1215 
1216                 if (Diff.QuadPart > Int32x32To64(15000, 10000))
1217                 {
1218                      /* release spin lock */
1219                      KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1220 
1221                      DPRINT1("DeviceID %S Instance %S TimeCreated %I64u Now %I64u Diff %I64u hung\n", DeviceEntry->DeviceName, DeviceEntry->Instance, DeviceEntry->TimeCreated.QuadPart, Time.QuadPart, Diff.QuadPart);
1222 
1223                      /* deactivate interfaces */
1224                      //KspEnableBusDeviceInterface(DeviceEntry, FALSE);
1225 
1226                      /* re-acquire lock */
1227                      KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1228 
1229                      /* pending remove device object */
1230                      DeviceEntry->DeviceState = StopPending;
1231 
1232                      /* perform invalidation */
1233                      DoInvalidate = TRUE;
1234                 }
1235             }
1236             else if (DeviceEntry->DeviceState == Started)
1237             {
1238                 /* release spin lock */
1239                 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1240 
1241                 /* found pending irps */
1242                 KspCompletePendingIrps(DeviceEntry, STATUS_REPARSE);
1243 
1244                 /* re-acquire lock */
1245                 KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1246             }
1247         }
1248 
1249 
1250         /* move to next */
1251         Entry = Entry->Flink;
1252     }
1253 
1254    /* release lock */
1255     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1256 
1257     if (DoInvalidate)
1258     {
1259         /* invalidate device relations */
1260         IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1261     }
1262 
1263     Time.QuadPart = Int32x32To64(5000, -10000);
1264     KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1265 }
1266 
1267 VOID
1268 NTAPI
1269 KspBusDpcRoutine(
1270     IN PKDPC Dpc,
1271     IN PVOID DeferredContext OPTIONAL,
1272     IN PVOID SystemArgument1 OPTIONAL,
1273     IN PVOID SystemArgument2 OPTIONAL)
1274 {
1275     /* get device extension */
1276     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeferredContext;
1277 
1278     /* queue the item */
1279     ExQueueWorkItem(&BusDeviceExtension->WorkItem, DelayedWorkQueue);
1280 }
1281 
1282 VOID
1283 NTAPI
1284 KspRemoveBusInterface(
1285     PVOID Ctx)
1286 {
1287     PBUS_INSTALL_ENUM_CONTEXT Context =(PBUS_INSTALL_ENUM_CONTEXT)Ctx;
1288 
1289     /* TODO
1290      * get SWENUM_INSTALL_INTERFACE struct
1291      * open device key and delete the keys
1292      */
1293 
1294     UNIMPLEMENTED;
1295 
1296     /* set status */
1297     Context->Status = STATUS_NOT_IMPLEMENTED;
1298 
1299 
1300     /* signal completion */
1301     KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
1302 }
1303 
1304 NTSTATUS
1305 KspQueryBusRelations(
1306     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
1307     IN PIRP Irp)
1308 {
1309     PDEVICE_RELATIONS DeviceRelations;
1310     PLIST_ENTRY Entry;
1311     PBUS_DEVICE_ENTRY DeviceEntry;
1312     ULONG Count = 0, Length;
1313     KIRQL OldLevel;
1314 
1315     /* acquire lock */
1316     KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1317 
1318     /* first scan all device entries */
1319     Entry = BusDeviceExtension->Common.Entry.Flink;
1320 
1321     while(Entry != &BusDeviceExtension->Common.Entry)
1322     {
1323         /* get offset to device entry */
1324         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1325 
1326         /* is there a pdo yet */
1327         if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1328         {
1329             /* increment count */
1330             Count++;
1331         }
1332 
1333         /* move to next entry */
1334         Entry = Entry->Flink;
1335     }
1336 
1337     /* calculate length */
1338     Length = sizeof(DEVICE_RELATIONS) + (Count > 1 ? sizeof(PDEVICE_OBJECT) * (Count-1) : 0);
1339 
1340     /* allocate device relations */
1341     DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, Length);
1342 
1343     if (!DeviceRelations)
1344     {
1345         /* not enough memory */
1346         KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1347         return STATUS_INSUFFICIENT_RESOURCES;
1348     }
1349 
1350     /* rescan device entries */
1351     Entry = BusDeviceExtension->Common.Entry.Flink;
1352 
1353     while(Entry != &BusDeviceExtension->Common.Entry)
1354     {
1355         /* get offset to device entry */
1356         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1357 
1358         /* is there a pdo yet */
1359         if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1360         {
1361             /* store pdo */
1362             DeviceRelations->Objects[DeviceRelations->Count] = DeviceEntry->PDO;
1363 
1364             /* reference device object */
1365             ObReferenceObject(DeviceEntry->PDO);
1366 
1367             /* increment pdo count */
1368             DeviceRelations->Count++;
1369         }
1370 
1371         /* move to next entry */
1372         Entry = Entry->Flink;
1373     }
1374 
1375     /* release lock */
1376     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1377 
1378     /* FIXME handle existing device relations */
1379     ASSERT(Irp->IoStatus.Information == 0);
1380 
1381     /* store device relations */
1382     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1383 
1384     /* done */
1385     return STATUS_SUCCESS;
1386 }
1387 
1388 //------------------------------------------------------------------------------------
1389 
1390 /*
1391     @implemented
1392 */
1393 
1394 KSDDKAPI
1395 NTSTATUS
1396 NTAPI
1397 KsGetBusEnumIdentifier(
1398     IN PIRP Irp)
1399 {
1400     PDEV_EXTENSION DeviceExtension;
1401     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1402     PIO_STACK_LOCATION IoStack;
1403     SIZE_T Length;
1404     NTSTATUS Status;
1405     LPWSTR Buffer;
1406 
1407     DPRINT("KsGetBusEnumIdentifier\n");
1408 
1409     /* get stack location */
1410     IoStack = IoGetCurrentIrpStackLocation(Irp);
1411 
1412     /* sanity checks */
1413     ASSERT(IoStack->DeviceObject);
1414     ASSERT(IoStack->DeviceObject->DeviceExtension);
1415 
1416     /* get device extension */
1417     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1418 
1419     /* get bus device extension */
1420     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1421 
1422     /* sanity checks */
1423     ASSERT(BusDeviceExtension);
1424     ASSERT(BusDeviceExtension->Common.IsBus);
1425 
1426     if (!BusDeviceExtension)
1427     {
1428         /* invalid parameter */
1429         return STATUS_INVALID_PARAMETER;
1430     }
1431 
1432     /* get length */
1433     Length = (wcslen(BusDeviceExtension->BusIdentifier)+1) * sizeof(WCHAR);
1434 
1435     /* is there an output buffer provided */
1436     if (IoStack->Parameters.DeviceIoControl.InputBufferLength)
1437     {
1438         if (Length > IoStack->Parameters.DeviceIoControl.InputBufferLength)
1439         {
1440             /* buffer is too small */
1441             return STATUS_BUFFER_TOO_SMALL;
1442         }
1443 
1444         /* now allocate buffer */
1445         Buffer = AllocateItem(NonPagedPool, Length);
1446         if (!Buffer)
1447         {
1448             /* no memory */
1449             Status = STATUS_INSUFFICIENT_RESOURCES;
1450         }
1451         else
1452         {
1453             /* copy bus identifier */
1454             wcscpy(Buffer, BusDeviceExtension->BusIdentifier);
1455 
1456             /* store buffer */
1457             Irp->AssociatedIrp.SystemBuffer = Buffer;
1458 
1459             /* set flag that buffer gets copied back */
1460             Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
1461 
1462             /* done */
1463             Status = STATUS_SUCCESS;
1464         }
1465     }
1466     else
1467     {
1468         /* no buffer provided */
1469         Status = STATUS_BUFFER_OVERFLOW;
1470     }
1471 
1472     /* done */
1473     Irp->IoStatus.Status = Status;
1474     return Status;
1475 }
1476 
1477 /*
1478     @implemented
1479 */
1480 KSDDKAPI
1481 NTSTATUS
1482 NTAPI
1483 KsGetBusEnumParentFDOFromChildPDO(
1484     IN PDEVICE_OBJECT DeviceObject,
1485     OUT PDEVICE_OBJECT *FunctionalDeviceObject)
1486 {
1487     PDEV_EXTENSION DeviceExtension;
1488 
1489     DPRINT("KsGetBusEnumParentFDOFromChildPDO\n");
1490 
1491     /* get device extension */
1492     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1493 
1494     /* check if this is child pdo */
1495     if (DeviceExtension->Ext->IsBus == FALSE)
1496     {
1497         /* return bus device object */
1498         *FunctionalDeviceObject = DeviceExtension->Ext->BusDeviceExtension->BusDeviceObject;
1499 
1500         /* done */
1501         return STATUS_SUCCESS;
1502     }
1503 
1504     /* invalid parameter */
1505     return STATUS_INVALID_PARAMETER;
1506 }
1507 
1508 
1509 /*
1510     @implemented
1511 */
1512 KSDDKAPI
1513 NTSTATUS
1514 NTAPI
1515 KsCreateBusEnumObject(
1516     IN PWCHAR BusIdentifier,
1517     IN PDEVICE_OBJECT BusDeviceObject,
1518     IN PDEVICE_OBJECT PhysicalDeviceObject,
1519     IN PDEVICE_OBJECT PnpDeviceObject OPTIONAL,
1520     IN REFGUID InterfaceGuid OPTIONAL,
1521     IN PWCHAR ServiceRelativePath OPTIONAL)
1522 {
1523     SIZE_T Length;
1524     NTSTATUS Status = STATUS_SUCCESS;
1525     UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
1526     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1527     PDEV_EXTENSION DeviceExtension;
1528     PBUS_DEVICE_ENTRY DeviceEntry;
1529     PLIST_ENTRY Entry;
1530     KIRQL OldLevel;
1531 
1532     DPRINT1("KsCreateBusEnumObject %S BusDeviceObject %p\n", ServiceRelativePath, BusDeviceObject);
1533 
1534     /* calculate sizeof bus enum device extension */
1535     Length = wcslen(BusIdentifier) * sizeof(WCHAR);
1536     Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
1537 
1538     BusDeviceExtension = AllocateItem(NonPagedPool, Length);
1539     if (!BusDeviceExtension)
1540     {
1541         /* not enough memory */
1542 
1543         return STATUS_INSUFFICIENT_RESOURCES;
1544     }
1545 
1546     /* get device extension */
1547     DeviceExtension = (PDEV_EXTENSION)BusDeviceObject->DeviceExtension;
1548 
1549     /* store bus device extension */
1550     DeviceExtension->Ext = (PCOMMON_DEVICE_EXTENSION)BusDeviceExtension;
1551 
1552     DPRINT("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
1553 
1554 
1555     /* zero device extension */
1556     RtlZeroMemory(BusDeviceExtension, sizeof(BUS_ENUM_DEVICE_EXTENSION));
1557 
1558     /* initialize bus device extension */
1559     wcscpy(BusDeviceExtension->BusIdentifier, BusIdentifier);
1560 
1561     /* allocate service path string */
1562     Length = ServiceKeyPath.MaximumLength;
1563     Length += BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName.MaximumLength;
1564 
1565     if (ServiceRelativePath)
1566     {
1567         /* relative path for devices */
1568         Length += (wcslen(ServiceRelativePath) + 2) * sizeof(WCHAR);
1569     }
1570 
1571     BusDeviceExtension->ServicePath.Length = 0;
1572     BusDeviceExtension->ServicePath.MaximumLength = (USHORT)Length;
1573     BusDeviceExtension->ServicePath.Buffer = AllocateItem(NonPagedPool, Length);
1574 
1575     if (!BusDeviceExtension->ServicePath.Buffer)
1576     {
1577         /* not enough memory */
1578         FreeItem(BusDeviceExtension);
1579 
1580         return STATUS_INSUFFICIENT_RESOURCES;
1581     }
1582 
1583     RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &ServiceKeyPath);
1584     RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName);
1585 
1586     if (ServiceRelativePath)
1587     {
1588         RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, L"\\");
1589         RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, ServiceRelativePath);
1590     }
1591 
1592     if (InterfaceGuid)
1593     {
1594         /* register an device interface */
1595         Status = IoRegisterDeviceInterface(PhysicalDeviceObject, InterfaceGuid, NULL, &BusDeviceExtension->DeviceInterfaceLink);
1596 
1597         /* check for success */
1598         if (!NT_SUCCESS(Status))
1599         {
1600             DPRINT1("IoRegisterDeviceInterface failed Status %lx\n", Status);
1601             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1602             FreeItem(BusDeviceExtension);
1603             return Status;
1604         }
1605 
1606         /* now enable device interface */
1607         Status = IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, TRUE);
1608 
1609         if (!NT_SUCCESS(Status))
1610         {
1611             DPRINT1("IoSetDeviceInterfaceState failed Status %lx\n", Status);
1612             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1613             FreeItem(BusDeviceExtension);
1614             return Status;
1615         }
1616     }
1617 
1618     /* initialize common device extension */
1619     BusDeviceExtension->Common.BusDeviceExtension = NULL;
1620     BusDeviceExtension->Common.DeviceObjectReferenceCount = 1;
1621     BusDeviceExtension->Common.DeviceReferenceCount = 1;
1622     BusDeviceExtension->Common.IsBus = TRUE;
1623     InitializeListHead(&BusDeviceExtension->Common.Entry);
1624 
1625     /* store device objects */
1626     BusDeviceExtension->BusDeviceObject = BusDeviceObject;
1627     BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
1628 
1629     /* initialize lock */
1630     KeInitializeSpinLock(&BusDeviceExtension->Lock);
1631 
1632     /* initialize timer */
1633     KeInitializeTimer(&BusDeviceExtension->Timer);
1634 
1635     /* initialize dpc */
1636     KeInitializeDpc(&BusDeviceExtension->Dpc, KspBusDpcRoutine, (PVOID)BusDeviceExtension);
1637 
1638     /* initialize event */
1639     KeInitializeEvent(&BusDeviceExtension->Event, SynchronizationEvent, FALSE);
1640 
1641     /* initialize work item */
1642     ExInitializeWorkItem(&BusDeviceExtension->WorkItem, KspBusWorkerRoutine, (PVOID)BusDeviceExtension);
1643 
1644     if (!PnpDeviceObject)
1645     {
1646         /* attach device */
1647         BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
1648 
1649         if (!BusDeviceExtension->PnpDeviceObject)
1650         {
1651             /* failed to attach device */
1652             DPRINT1("IoAttachDeviceToDeviceStack failed with %x\n", Status);
1653             if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1654             {
1655                 IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1656                 RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1657             }
1658 
1659             /* free device extension */
1660             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1661             FreeItem(BusDeviceExtension);
1662 
1663             return STATUS_DEVICE_REMOVED;
1664         }
1665 
1666         /* mark device as attached */
1667         BusDeviceExtension->DeviceAttached = TRUE;
1668     }
1669     else
1670     {
1671         /* directly attach */
1672         BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
1673     }
1674 
1675     /* now scan the bus */
1676     Status = KspScanBus(BusDeviceExtension);
1677 
1678     /* check for success */
1679     if (!NT_SUCCESS(Status))
1680     {
1681         /* failed to scan bus */
1682         if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1683         {
1684             IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1685             RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1686         }
1687 
1688         if (BusDeviceExtension->DeviceAttached)
1689         {
1690             /* detach device */
1691             IoDetachDevice(BusDeviceExtension->PnpDeviceObject);
1692         }
1693 
1694         /* free device extension */
1695         FreeItem(BusDeviceExtension->ServicePath.Buffer);
1696         FreeItem(BusDeviceExtension);
1697 
1698         return Status;
1699     }
1700 
1701     /* acquire device entry lock */
1702     KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1703 
1704     /* now iterate all device entries */
1705     Entry = BusDeviceExtension->Common.Entry.Flink;
1706     while(Entry != &BusDeviceExtension->Common.Entry)
1707     {
1708         /* get device entry */
1709         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1710         if (!DeviceEntry->PDO)
1711         {
1712             /* release device entry lock */
1713             KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1714 
1715             /* create pdo */
1716             Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1717 
1718             /* acquire device entry lock */
1719             KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1720 
1721             /* done */
1722             break;
1723         }
1724         /* move to next entry */
1725         Entry = Entry->Flink;
1726     }
1727 
1728     /* release device entry lock */
1729     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1730 
1731 
1732     /* invalidate device relations */
1733     IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1734     DPRINT("KsCreateBusEnumObject Status %x\n", Status);
1735     /* done */
1736     return Status;
1737 }
1738 
1739 /*
1740     @implemented
1741 */
1742 KSDDKAPI
1743 NTSTATUS
1744 NTAPI
1745 KsGetBusEnumPnpDeviceObject(
1746     IN PDEVICE_OBJECT DeviceObject,
1747     IN PDEVICE_OBJECT *PnpDeviceObject)
1748 {
1749     PDEV_EXTENSION DeviceExtension;
1750     PCOMMON_DEVICE_EXTENSION CommonDeviceExtension;
1751     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1752 
1753     DPRINT("KsGetBusEnumPnpDeviceObject\n");
1754 
1755     if (!DeviceObject->DeviceExtension)
1756     {
1757         /* invalid parameter */
1758         return STATUS_INVALID_PARAMETER;
1759     }
1760 
1761     /* get device extension */
1762     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1763 
1764     /* get common device extension */
1765     CommonDeviceExtension = DeviceExtension->Ext;
1766 
1767     if (!CommonDeviceExtension)
1768     {
1769         /* invalid parameter */
1770         return STATUS_INVALID_PARAMETER;
1771     }
1772 
1773     if (!CommonDeviceExtension->IsBus)
1774     {
1775         /* getting pnp device object is only supported for software bus device object */
1776        return STATUS_INVALID_PARAMETER;
1777     }
1778 
1779     /* sanity checks */
1780     ASSERT(CommonDeviceExtension);
1781     ASSERT(CommonDeviceExtension->IsBus);
1782 
1783     /* cast to bus device extension */
1784     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)CommonDeviceExtension;
1785 
1786     /* store result */
1787     *PnpDeviceObject = BusDeviceExtension->PnpDeviceObject;
1788 
1789     /* done */
1790     return STATUS_SUCCESS;
1791 }
1792 
1793 /*
1794     @implemented
1795 */
1796 KSDDKAPI
1797 NTSTATUS
1798 NTAPI
1799 KsInstallBusEnumInterface(
1800     PIRP Irp)
1801 {
1802     BUS_INSTALL_ENUM_CONTEXT Context;
1803     KPROCESSOR_MODE Mode;
1804     LUID luid;
1805     PIO_STACK_LOCATION IoStack;
1806     PDEV_EXTENSION DeviceExtension;
1807     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1808 
1809     DPRINT("KsInstallBusEnumInterface\n");
1810 
1811     /* get current irp stack location */
1812     IoStack = IoGetCurrentIrpStackLocation(Irp);
1813 
1814     /* get previous mode */
1815     Mode = ExGetPreviousMode();
1816 
1817     /* convert to luid */
1818     luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
1819 
1820     /* perform access check */
1821     if (!SeSinglePrivilegeCheck(luid, Mode))
1822     {
1823         /* FIXME insufficient privileges */
1824         //return STATUS_PRIVILEGE_NOT_HELD;
1825     }
1826 
1827     /* get device extension */
1828     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1829 
1830     /* get bus device extension */
1831     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1832 
1833 
1834     /* initialize context */
1835     Context.Irp = Irp;
1836     KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
1837     Context.BusDeviceExtension = BusDeviceExtension;
1838     ExInitializeWorkItem(&Context.WorkItem, KspInstallBusEnumInterface, (PVOID)&Context);
1839 
1840     /* queue the work item */
1841     ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
1842     /* wait for completion */
1843     KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
1844 
1845     /* store result */
1846     Irp->IoStatus.Status = Context.Status;
1847 
1848     /* done */
1849     return Context.Status;
1850 }
1851 
1852 /*
1853     @implemented
1854 */
1855 KSDDKAPI
1856 NTSTATUS
1857 NTAPI
1858 KsIsBusEnumChildDevice(
1859     IN PDEVICE_OBJECT DeviceObject,
1860     OUT PBOOLEAN ChildDevice)
1861 {
1862     PDEV_EXTENSION DeviceExtension;
1863     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1864 
1865     DPRINT("KsIsBusEnumChildDevice %p\n", DeviceObject);
1866 
1867     /* get device extension */
1868     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1869 
1870     /* get bus device extension */
1871     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1872 
1873     if (!BusDeviceExtension)
1874     {
1875         /* not a bus device */
1876         return STATUS_INVALID_PARAMETER;
1877     }
1878 
1879     /* store result */
1880     *ChildDevice = (BusDeviceExtension->Common.IsBus == FALSE);
1881 
1882     return STATUS_SUCCESS;
1883 }
1884 
1885 /*
1886     @implemented
1887 */
1888 KSDDKAPI
1889 NTSTATUS
1890 NTAPI
1891 KsServiceBusEnumCreateRequest(
1892     IN PDEVICE_OBJECT DeviceObject,
1893     IN OUT PIRP Irp)
1894 {
1895     PLIST_ENTRY Entry;
1896     PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* fix gcc */
1897     PIO_STACK_LOCATION IoStack;
1898     BOOLEAN ItemExists = FALSE;
1899     PDEV_EXTENSION DeviceExtension;
1900     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1901     //PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
1902     NTSTATUS Status;
1903     LARGE_INTEGER Time;
1904 
1905     /* FIXME: locks */
1906 
1907     /* get device extension */
1908     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1909 
1910     /* get bus device extension */
1911     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1912 
1913     /* get current irp stack location */
1914     IoStack = IoGetCurrentIrpStackLocation(Irp);
1915 
1916     /* sanity checks */
1917     ASSERT(IoStack->FileObject);
1918     if (IoStack->FileObject->FileName.Buffer == NULL)
1919     {
1920          DPRINT("KsServiceBusEnumCreateRequest PNP Hack\n");
1921          Irp->IoStatus.Status = STATUS_SUCCESS;
1922          return STATUS_SUCCESS;
1923     }
1924 
1925     ASSERT(IoStack->FileObject->FileName.Buffer);
1926 
1927     DPRINT1("KsServiceBusEnumCreateRequest IRP %p Name %wZ\n", Irp, &IoStack->FileObject->FileName);
1928 
1929     /* scan list and check if it is already present */
1930     Entry = BusDeviceExtension->Common.Entry.Flink;
1931 
1932     while(Entry != &BusDeviceExtension->Common.Entry)
1933     {
1934         /* get real offset */
1935         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1936 
1937         /* check if name matches */
1938         if (!wcsicmp(DeviceEntry->DeviceName, IoStack->FileObject->FileName.Buffer + 1))
1939         {
1940             /* item already exists */
1941             ItemExists = TRUE;
1942             break;
1943         }
1944 
1945         /* move to next entry */
1946         Entry = Entry->Flink;
1947     }
1948 
1949     if (!ItemExists)
1950     {
1951         /* interface not registered */
1952         DPRINT1("Interface %wZ not registered\n", &IoStack->FileObject->FileName);
1953         return STATUS_OBJECT_NAME_NOT_FOUND;
1954     }
1955 
1956     /*  is there a pdo yet */
1957     if (DeviceEntry->PDO)
1958     {
1959         if (DeviceEntry->DeviceState == Started)
1960         {
1961             /* issue reparse */
1962             Status =  KspDoReparseForIrp(Irp, DeviceEntry);
1963             DPRINT("REPARSE Irp %p '%wZ'\n", Irp, &IoStack->FileObject->FileName);
1964 
1965             Irp->IoStatus.Status = Status;
1966             Irp->IoStatus.Information = IO_REPARSE;
1967             return Status;
1968         }
1969 
1970         /* delay processing until pnp is finished with enumeration */
1971         IoMarkIrpPending(Irp);
1972 
1973         /* insert into irp pending list */
1974         InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
1975 
1976         Time.QuadPart = Int32x32To64(1500, -10000);
1977         DbgPrint("PENDING Irp %p %wZ DeviceState %d\n", Irp, &IoStack->FileObject->FileName, DeviceEntry->DeviceState);
1978 
1979 
1980         /* set timer */
1981         KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1982 
1983         /* done for now */
1984         return STATUS_PENDING;
1985 
1986     }
1987     else
1988     {
1989         /* time to create PDO */
1990         Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1991 
1992         if (!NT_SUCCESS(Status))
1993         {
1994             /* failed to create PDO */
1995             DPRINT1("KsServiceBusEnumCreateRequest failed to create PDO with %x\n", Status);
1996             return Status;
1997         }
1998         DPRINT("PENDING CREATE Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
1999 
2000         /* delay processing until pnp is finished with enumeration */
2001         IoMarkIrpPending(Irp);
2002 
2003         /* insert into irp pending list */
2004         InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
2005 
2006         /* invalidate device relations */
2007         IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
2008 
2009         /* done for now */
2010         return STATUS_PENDING;
2011     }
2012 }
2013 
2014 /*
2015     @implemented
2016 */
2017 KSDDKAPI
2018 NTSTATUS
2019 NTAPI
2020 KsServiceBusEnumPnpRequest(
2021     IN PDEVICE_OBJECT DeviceObject,
2022     IN OUT PIRP Irp)
2023 {
2024     PDEV_EXTENSION DeviceExtension;
2025     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
2026     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
2027     PIO_STACK_LOCATION IoStack;
2028     NTSTATUS Status;
2029     LARGE_INTEGER Time;
2030     PDEVICE_RELATIONS DeviceRelation;
2031     PBUS_DEVICE_ENTRY DeviceEntry;
2032 
2033     /* get device extension */
2034     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
2035 
2036     /* get bus device extension */
2037     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
2038 
2039     /* get current irp stack location */
2040     IoStack = IoGetCurrentIrpStackLocation(Irp);
2041 
2042     if (BusDeviceExtension->Common.IsBus)
2043     {
2044         if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
2045         {
2046             /* no op for bus driver */
2047             Status = STATUS_SUCCESS;
2048         }
2049         else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
2050         {
2051             /* handle bus device relations */
2052             ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == BusRelations);
2053 
2054             Status = KspQueryBusRelations(BusDeviceExtension, Irp);
2055         }
2056         else
2057         {
2058             /* get default status */
2059             Status = Irp->IoStatus.Status;
2060         }
2061     }
2062     else
2063     {
2064         /* get child device extension */
2065         ChildDeviceExtension = DeviceExtension->Ext;
2066 
2067         /* get bus device extension */
2068         BusDeviceExtension = ChildDeviceExtension->BusDeviceExtension;
2069 
2070         if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
2071         {
2072             /* query id */
2073             Status = KspQueryId(ChildDeviceExtension, Irp);
2074         }
2075         else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
2076         {
2077             ASSERT(ChildDeviceExtension->DeviceEntry->DeviceState != Started || ChildDeviceExtension->DeviceEntry->DeviceState == NotStarted);
2078             ASSERT(ChildDeviceExtension->DeviceEntry->PDO == DeviceObject);
2079 
2080             /* backup device entry */
2081             DeviceEntry = ChildDeviceExtension->DeviceEntry;
2082 
2083             /* free device extension */
2084             FreeItem(ChildDeviceExtension);
2085 
2086             /* clear PDO reference */
2087             DeviceEntry->PDO = NULL;
2088 
2089             /* delete the device */
2090             IoDeleteDevice(DeviceObject);
2091 
2092             if (DeviceEntry->PDODeviceName)
2093             {
2094                 /* delete pdo device name */
2095                 FreeItem(DeviceEntry->PDODeviceName);
2096 
2097                 /* set to null */
2098                 DeviceEntry->PDODeviceName = NULL;
2099             }
2100 
2101             /* set state no notstarted */
2102             DeviceEntry->DeviceState = NotStarted;
2103 
2104             /* complete pending irps */
2105             KspCompletePendingIrps(DeviceEntry, STATUS_DEVICE_REMOVED);
2106 
2107             /* done */
2108             Status = STATUS_SUCCESS;
2109         }
2110         else if (IoStack->MinorFunction == IRP_MN_QUERY_BUS_INFORMATION)
2111         {
2112             /* query bus information */
2113             Status = KspQueryBusInformation(ChildDeviceExtension, Irp);
2114         }
2115         else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES)
2116         {
2117             /* no op */
2118             Status = STATUS_SUCCESS;
2119         }
2120         else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
2121         {
2122             /* no op */
2123             Status = STATUS_SUCCESS;
2124         }
2125         else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
2126         {
2127             /* start bus */
2128             Status = KspStartBusDevice(DeviceObject, ChildDeviceExtension, Irp);
2129             if (NT_SUCCESS(Status))
2130             {
2131                 /* complete pending irps*/
2132                 KspCompletePendingIrps(ChildDeviceExtension->DeviceEntry, STATUS_REPARSE);
2133             }
2134 
2135             /* set time out */
2136             Time.QuadPart = Int32x32To64(1500, -10000);
2137 
2138             /* sanity check */
2139             ASSERT(BusDeviceExtension);
2140 
2141             /* set timer */
2142             KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
2143         }
2144         else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES)
2145         {
2146             /* query capabilities */
2147             Status = KspQueryBusDeviceCapabilities(ChildDeviceExtension, Irp);
2148         }
2149         else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
2150         {
2151             /* query pnp state */
2152             Status = KspQueryBusDevicePnpState(ChildDeviceExtension, Irp);
2153         }
2154         else if (IoStack->MinorFunction == IRP_MN_QUERY_INTERFACE)
2155         {
2156             /* query interface */
2157             Status = KspQueryBusDeviceInterface(ChildDeviceExtension, Irp);
2158         }
2159         else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS && IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
2160         {
2161             /* handle target device relations */
2162             ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation);
2163             ASSERT(Irp->IoStatus.Information == 0);
2164 
2165             /* allocate device relation */
2166             DeviceRelation = AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
2167             if (DeviceRelation)
2168             {
2169                 DeviceRelation->Count = 1;
2170                 DeviceRelation->Objects[0] = DeviceObject;
2171 
2172                 /* reference self */
2173                 ObReferenceObject(DeviceObject);
2174 
2175                 /* store result */
2176                 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
2177 
2178                 /* done */
2179                 Status = STATUS_SUCCESS;
2180             }
2181             else
2182             {
2183                 /* no memory */
2184                 Status = STATUS_INSUFFICIENT_RESOURCES;
2185             }
2186         }
2187         else
2188         {
2189             /* get default status */
2190             Status = Irp->IoStatus.Status;
2191         }
2192     }
2193 
2194     DPRINT("KsServiceBusEnumPnpRequest %p Bus %u Function %x Status %x\n", DeviceObject, BusDeviceExtension->Common.IsBus, IoStack->MinorFunction, Status);
2195     Irp->IoStatus.Status = Status;
2196     return Status;
2197 }
2198 
2199 /*
2200     @implemented
2201 */
2202 KSDDKAPI
2203 NTSTATUS
2204 NTAPI
2205 KsRemoveBusEnumInterface(
2206     IN PIRP Irp)
2207 {
2208     KPROCESSOR_MODE Mode;
2209     LUID luid;
2210     BUS_INSTALL_ENUM_CONTEXT Ctx;
2211     PDEV_EXTENSION DeviceExtension;
2212     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
2213     PIO_STACK_LOCATION IoStack;
2214 
2215     DPRINT("KsRemoveBusEnumInterface\n");
2216 
2217     /* get io stack location */
2218     IoStack = IoGetCurrentIrpStackLocation(Irp);
2219 
2220     /* get device extension */
2221     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
2222 
2223     /* get bus device extension */
2224     BusDeviceExtension = DeviceExtension->Ext->BusDeviceExtension;
2225 
2226     /* get previous mode */
2227     Mode = ExGetPreviousMode();
2228 
2229     /* convert to luid */
2230     luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
2231 
2232     /* perform access check */
2233     if (!SeSinglePrivilegeCheck(luid, Mode))
2234     {
2235         /* insufficient privileges */
2236         return STATUS_PRIVILEGE_NOT_HELD;
2237     }
2238 
2239     /* initialize context */
2240     KeInitializeEvent(&Ctx.Event, NotificationEvent, FALSE);
2241     Ctx.Irp = Irp;
2242     Ctx.BusDeviceExtension = BusDeviceExtension;
2243     ExInitializeWorkItem(&Ctx.WorkItem, KspRemoveBusInterface, (PVOID)&Ctx);
2244 
2245     /* now queue the work item */
2246     ExQueueWorkItem(&Ctx.WorkItem, DelayedWorkQueue);
2247 
2248     /* wait for completion */
2249     KeWaitForSingleObject(&Ctx.Event, Executive, KernelMode, FALSE, NULL);
2250 
2251     /* return result */
2252     return Ctx.Status;
2253 }
2254