xref: /reactos/drivers/ksfilter/ks/swenum.c (revision d6eebaa4)
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     KeQueryTickCount(&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     KeQueryTickCount(&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     KeQueryTickCount(&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) * KeQueryTimeIncrement();
1215 
1216                 /* wait for 15 sec */
1217                 if (Diff.QuadPart > Int32x32To64(15000, 10000))
1218                 {
1219                      /* release spin lock */
1220                      KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1221 
1222                      DPRINT1("DeviceID %S Instance %S TimeCreated %I64u Now %I64u Diff %I64u hung\n",
1223                         DeviceEntry->DeviceName,
1224                         DeviceEntry->Instance,
1225                         DeviceEntry->TimeCreated.QuadPart * KeQueryTimeIncrement(),
1226                         Time.QuadPart * KeQueryTimeIncrement(),
1227                         Diff.QuadPart);
1228 
1229                      /* deactivate interfaces */
1230                      //KspEnableBusDeviceInterface(DeviceEntry, FALSE);
1231 
1232                      /* re-acquire lock */
1233                      KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1234 
1235                      /* pending remove device object */
1236                      DeviceEntry->DeviceState = StopPending;
1237 
1238                      /* perform invalidation */
1239                      DoInvalidate = TRUE;
1240                 }
1241             }
1242             else if (DeviceEntry->DeviceState == Started)
1243             {
1244                 /* release spin lock */
1245                 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1246 
1247                 /* found pending irps */
1248                 KspCompletePendingIrps(DeviceEntry, STATUS_REPARSE);
1249 
1250                 /* re-acquire lock */
1251                 KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1252             }
1253         }
1254 
1255 
1256         /* move to next */
1257         Entry = Entry->Flink;
1258     }
1259 
1260    /* release lock */
1261     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1262 
1263     if (DoInvalidate)
1264     {
1265         /* invalidate device relations */
1266         IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1267     }
1268 
1269     Time.QuadPart = Int32x32To64(5000, -10000);
1270     KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1271 }
1272 
1273 VOID
1274 NTAPI
1275 KspBusDpcRoutine(
1276     IN PKDPC Dpc,
1277     IN PVOID DeferredContext OPTIONAL,
1278     IN PVOID SystemArgument1 OPTIONAL,
1279     IN PVOID SystemArgument2 OPTIONAL)
1280 {
1281     /* get device extension */
1282     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeferredContext;
1283 
1284     /* queue the item */
1285     ExQueueWorkItem(&BusDeviceExtension->WorkItem, DelayedWorkQueue);
1286 }
1287 
1288 VOID
1289 NTAPI
1290 KspRemoveBusInterface(
1291     PVOID Ctx)
1292 {
1293     PBUS_INSTALL_ENUM_CONTEXT Context =(PBUS_INSTALL_ENUM_CONTEXT)Ctx;
1294 
1295     /* TODO
1296      * get SWENUM_INSTALL_INTERFACE struct
1297      * open device key and delete the keys
1298      */
1299 
1300     UNIMPLEMENTED;
1301 
1302     /* set status */
1303     Context->Status = STATUS_NOT_IMPLEMENTED;
1304 
1305 
1306     /* signal completion */
1307     KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
1308 }
1309 
1310 NTSTATUS
1311 KspQueryBusRelations(
1312     IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
1313     IN PIRP Irp)
1314 {
1315     PDEVICE_RELATIONS DeviceRelations;
1316     PLIST_ENTRY Entry;
1317     PBUS_DEVICE_ENTRY DeviceEntry;
1318     ULONG Count = 0, Length;
1319     KIRQL OldLevel;
1320 
1321     /* acquire lock */
1322     KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1323 
1324     /* first scan all device entries */
1325     Entry = BusDeviceExtension->Common.Entry.Flink;
1326 
1327     while(Entry != &BusDeviceExtension->Common.Entry)
1328     {
1329         /* get offset to device entry */
1330         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1331 
1332         /* is there a pdo yet */
1333         if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1334         {
1335             /* increment count */
1336             Count++;
1337         }
1338 
1339         /* move to next entry */
1340         Entry = Entry->Flink;
1341     }
1342 
1343     /* calculate length */
1344     Length = sizeof(DEVICE_RELATIONS) + (Count > 1 ? sizeof(PDEVICE_OBJECT) * (Count-1) : 0);
1345 
1346     /* allocate device relations */
1347     DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, Length);
1348 
1349     if (!DeviceRelations)
1350     {
1351         /* not enough memory */
1352         KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1353         return STATUS_INSUFFICIENT_RESOURCES;
1354     }
1355 
1356     /* rescan device entries */
1357     Entry = BusDeviceExtension->Common.Entry.Flink;
1358 
1359     while(Entry != &BusDeviceExtension->Common.Entry)
1360     {
1361         /* get offset to device entry */
1362         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1363 
1364         /* is there a pdo yet */
1365         if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1366         {
1367             /* store pdo */
1368             DeviceRelations->Objects[DeviceRelations->Count] = DeviceEntry->PDO;
1369 
1370             /* reference device object */
1371             ObReferenceObject(DeviceEntry->PDO);
1372 
1373             /* increment pdo count */
1374             DeviceRelations->Count++;
1375         }
1376 
1377         /* move to next entry */
1378         Entry = Entry->Flink;
1379     }
1380 
1381     /* release lock */
1382     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1383 
1384     /* FIXME handle existing device relations */
1385     ASSERT(Irp->IoStatus.Information == 0);
1386 
1387     /* store device relations */
1388     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1389 
1390     /* done */
1391     return STATUS_SUCCESS;
1392 }
1393 
1394 //------------------------------------------------------------------------------------
1395 
1396 /*
1397     @implemented
1398 */
1399 
1400 KSDDKAPI
1401 NTSTATUS
1402 NTAPI
1403 KsGetBusEnumIdentifier(
1404     IN PIRP Irp)
1405 {
1406     PDEV_EXTENSION DeviceExtension;
1407     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1408     PIO_STACK_LOCATION IoStack;
1409     SIZE_T Length;
1410     NTSTATUS Status;
1411     LPWSTR Buffer;
1412 
1413     DPRINT("KsGetBusEnumIdentifier\n");
1414 
1415     /* get stack location */
1416     IoStack = IoGetCurrentIrpStackLocation(Irp);
1417 
1418     /* sanity checks */
1419     ASSERT(IoStack->DeviceObject);
1420     ASSERT(IoStack->DeviceObject->DeviceExtension);
1421 
1422     /* get device extension */
1423     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1424 
1425     /* get bus device extension */
1426     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1427 
1428     /* sanity checks */
1429     ASSERT(BusDeviceExtension);
1430     ASSERT(BusDeviceExtension->Common.IsBus);
1431 
1432     if (!BusDeviceExtension)
1433     {
1434         /* invalid parameter */
1435         return STATUS_INVALID_PARAMETER;
1436     }
1437 
1438     /* get length */
1439     Length = (wcslen(BusDeviceExtension->BusIdentifier)+1) * sizeof(WCHAR);
1440 
1441     /* is there an output buffer provided */
1442     if (IoStack->Parameters.DeviceIoControl.InputBufferLength)
1443     {
1444         if (Length > IoStack->Parameters.DeviceIoControl.InputBufferLength)
1445         {
1446             /* buffer is too small */
1447             return STATUS_BUFFER_TOO_SMALL;
1448         }
1449 
1450         /* now allocate buffer */
1451         Buffer = AllocateItem(NonPagedPool, Length);
1452         if (!Buffer)
1453         {
1454             /* no memory */
1455             Status = STATUS_INSUFFICIENT_RESOURCES;
1456         }
1457         else
1458         {
1459             /* copy bus identifier */
1460             wcscpy(Buffer, BusDeviceExtension->BusIdentifier);
1461 
1462             /* store buffer */
1463             Irp->AssociatedIrp.SystemBuffer = Buffer;
1464 
1465             /* set flag that buffer gets copied back */
1466             Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
1467 
1468             /* done */
1469             Status = STATUS_SUCCESS;
1470         }
1471     }
1472     else
1473     {
1474         /* no buffer provided */
1475         Status = STATUS_BUFFER_OVERFLOW;
1476     }
1477 
1478     /* done */
1479     Irp->IoStatus.Status = Status;
1480     return Status;
1481 }
1482 
1483 /*
1484     @implemented
1485 */
1486 KSDDKAPI
1487 NTSTATUS
1488 NTAPI
1489 KsGetBusEnumParentFDOFromChildPDO(
1490     IN PDEVICE_OBJECT DeviceObject,
1491     OUT PDEVICE_OBJECT *FunctionalDeviceObject)
1492 {
1493     PDEV_EXTENSION DeviceExtension;
1494 
1495     DPRINT("KsGetBusEnumParentFDOFromChildPDO\n");
1496 
1497     /* get device extension */
1498     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1499 
1500     /* check if this is child pdo */
1501     if (DeviceExtension->Ext->IsBus == FALSE)
1502     {
1503         /* return bus device object */
1504         *FunctionalDeviceObject = DeviceExtension->Ext->BusDeviceExtension->BusDeviceObject;
1505 
1506         /* done */
1507         return STATUS_SUCCESS;
1508     }
1509 
1510     /* invalid parameter */
1511     return STATUS_INVALID_PARAMETER;
1512 }
1513 
1514 
1515 /*
1516     @implemented
1517 */
1518 KSDDKAPI
1519 NTSTATUS
1520 NTAPI
1521 KsCreateBusEnumObject(
1522     IN PWCHAR BusIdentifier,
1523     IN PDEVICE_OBJECT BusDeviceObject,
1524     IN PDEVICE_OBJECT PhysicalDeviceObject,
1525     IN PDEVICE_OBJECT PnpDeviceObject OPTIONAL,
1526     IN REFGUID InterfaceGuid OPTIONAL,
1527     IN PWCHAR ServiceRelativePath OPTIONAL)
1528 {
1529     SIZE_T Length;
1530     NTSTATUS Status = STATUS_SUCCESS;
1531     UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
1532     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1533     PDEV_EXTENSION DeviceExtension;
1534     PBUS_DEVICE_ENTRY DeviceEntry;
1535     PLIST_ENTRY Entry;
1536     KIRQL OldLevel;
1537 
1538     DPRINT1("KsCreateBusEnumObject %S BusDeviceObject %p\n", ServiceRelativePath, BusDeviceObject);
1539 
1540     /* calculate sizeof bus enum device extension */
1541     Length = wcslen(BusIdentifier) * sizeof(WCHAR);
1542     Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
1543 
1544     BusDeviceExtension = AllocateItem(NonPagedPool, Length);
1545     if (!BusDeviceExtension)
1546     {
1547         /* not enough memory */
1548 
1549         return STATUS_INSUFFICIENT_RESOURCES;
1550     }
1551 
1552     /* get device extension */
1553     DeviceExtension = (PDEV_EXTENSION)BusDeviceObject->DeviceExtension;
1554 
1555     /* store bus device extension */
1556     DeviceExtension->Ext = (PCOMMON_DEVICE_EXTENSION)BusDeviceExtension;
1557 
1558     DPRINT("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
1559 
1560 
1561     /* zero device extension */
1562     RtlZeroMemory(BusDeviceExtension, sizeof(BUS_ENUM_DEVICE_EXTENSION));
1563 
1564     /* initialize bus device extension */
1565     wcscpy(BusDeviceExtension->BusIdentifier, BusIdentifier);
1566 
1567     /* allocate service path string */
1568     Length = ServiceKeyPath.MaximumLength;
1569     Length += BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName.MaximumLength;
1570 
1571     if (ServiceRelativePath)
1572     {
1573         /* relative path for devices */
1574         Length += (wcslen(ServiceRelativePath) + 2) * sizeof(WCHAR);
1575     }
1576 
1577     BusDeviceExtension->ServicePath.Length = 0;
1578     BusDeviceExtension->ServicePath.MaximumLength = (USHORT)Length;
1579     BusDeviceExtension->ServicePath.Buffer = AllocateItem(NonPagedPool, Length);
1580 
1581     if (!BusDeviceExtension->ServicePath.Buffer)
1582     {
1583         /* not enough memory */
1584         FreeItem(BusDeviceExtension);
1585 
1586         return STATUS_INSUFFICIENT_RESOURCES;
1587     }
1588 
1589     RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &ServiceKeyPath);
1590     RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName);
1591 
1592     if (ServiceRelativePath)
1593     {
1594         RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, L"\\");
1595         RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, ServiceRelativePath);
1596     }
1597 
1598     if (InterfaceGuid)
1599     {
1600         /* register an device interface */
1601         Status = IoRegisterDeviceInterface(PhysicalDeviceObject, InterfaceGuid, NULL, &BusDeviceExtension->DeviceInterfaceLink);
1602 
1603         /* check for success */
1604         if (!NT_SUCCESS(Status))
1605         {
1606             DPRINT1("IoRegisterDeviceInterface failed Status %lx\n", Status);
1607             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1608             FreeItem(BusDeviceExtension);
1609             return Status;
1610         }
1611 
1612         /* now enable device interface */
1613         Status = IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, TRUE);
1614 
1615         if (!NT_SUCCESS(Status))
1616         {
1617             DPRINT1("IoSetDeviceInterfaceState failed Status %lx\n", Status);
1618             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1619             FreeItem(BusDeviceExtension);
1620             return Status;
1621         }
1622     }
1623 
1624     /* initialize common device extension */
1625     BusDeviceExtension->Common.BusDeviceExtension = NULL;
1626     BusDeviceExtension->Common.DeviceObjectReferenceCount = 1;
1627     BusDeviceExtension->Common.DeviceReferenceCount = 1;
1628     BusDeviceExtension->Common.IsBus = TRUE;
1629     InitializeListHead(&BusDeviceExtension->Common.Entry);
1630 
1631     /* store device objects */
1632     BusDeviceExtension->BusDeviceObject = BusDeviceObject;
1633     BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
1634 
1635     /* initialize lock */
1636     KeInitializeSpinLock(&BusDeviceExtension->Lock);
1637 
1638     /* initialize timer */
1639     KeInitializeTimer(&BusDeviceExtension->Timer);
1640 
1641     /* initialize dpc */
1642     KeInitializeDpc(&BusDeviceExtension->Dpc, KspBusDpcRoutine, (PVOID)BusDeviceExtension);
1643 
1644     /* initialize event */
1645     KeInitializeEvent(&BusDeviceExtension->Event, SynchronizationEvent, FALSE);
1646 
1647     /* initialize work item */
1648     ExInitializeWorkItem(&BusDeviceExtension->WorkItem, KspBusWorkerRoutine, (PVOID)BusDeviceExtension);
1649 
1650     if (!PnpDeviceObject)
1651     {
1652         /* attach device */
1653         BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
1654 
1655         if (!BusDeviceExtension->PnpDeviceObject)
1656         {
1657             /* failed to attach device */
1658             DPRINT1("IoAttachDeviceToDeviceStack failed with %x\n", Status);
1659             if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1660             {
1661                 IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1662                 RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1663             }
1664 
1665             /* free device extension */
1666             FreeItem(BusDeviceExtension->ServicePath.Buffer);
1667             FreeItem(BusDeviceExtension);
1668 
1669             return STATUS_DEVICE_REMOVED;
1670         }
1671 
1672         /* mark device as attached */
1673         BusDeviceExtension->DeviceAttached = TRUE;
1674     }
1675     else
1676     {
1677         /* directly attach */
1678         BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
1679     }
1680 
1681     /* now scan the bus */
1682     Status = KspScanBus(BusDeviceExtension);
1683 
1684     /* check for success */
1685     if (!NT_SUCCESS(Status))
1686     {
1687         /* failed to scan bus */
1688         if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1689         {
1690             IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1691             RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1692         }
1693 
1694         if (BusDeviceExtension->DeviceAttached)
1695         {
1696             /* detach device */
1697             IoDetachDevice(BusDeviceExtension->PnpDeviceObject);
1698         }
1699 
1700         /* free device extension */
1701         FreeItem(BusDeviceExtension->ServicePath.Buffer);
1702         FreeItem(BusDeviceExtension);
1703 
1704         return Status;
1705     }
1706 
1707     /* acquire device entry lock */
1708     KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1709 
1710     /* now iterate all device entries */
1711     Entry = BusDeviceExtension->Common.Entry.Flink;
1712     while(Entry != &BusDeviceExtension->Common.Entry)
1713     {
1714         /* get device entry */
1715         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1716         if (!DeviceEntry->PDO)
1717         {
1718             /* release device entry lock */
1719             KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1720 
1721             /* create pdo */
1722             Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1723 
1724             /* acquire device entry lock */
1725             KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1726 
1727             /* done */
1728             break;
1729         }
1730         /* move to next entry */
1731         Entry = Entry->Flink;
1732     }
1733 
1734     /* release device entry lock */
1735     KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1736 
1737 
1738     /* invalidate device relations */
1739     IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1740     DPRINT("KsCreateBusEnumObject Status %x\n", Status);
1741     /* done */
1742     return Status;
1743 }
1744 
1745 /*
1746     @implemented
1747 */
1748 KSDDKAPI
1749 NTSTATUS
1750 NTAPI
1751 KsGetBusEnumPnpDeviceObject(
1752     IN PDEVICE_OBJECT DeviceObject,
1753     IN PDEVICE_OBJECT *PnpDeviceObject)
1754 {
1755     PDEV_EXTENSION DeviceExtension;
1756     PCOMMON_DEVICE_EXTENSION CommonDeviceExtension;
1757     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1758 
1759     DPRINT("KsGetBusEnumPnpDeviceObject\n");
1760 
1761     if (!DeviceObject->DeviceExtension)
1762     {
1763         /* invalid parameter */
1764         return STATUS_INVALID_PARAMETER;
1765     }
1766 
1767     /* get device extension */
1768     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1769 
1770     /* get common device extension */
1771     CommonDeviceExtension = DeviceExtension->Ext;
1772 
1773     if (!CommonDeviceExtension)
1774     {
1775         /* invalid parameter */
1776         return STATUS_INVALID_PARAMETER;
1777     }
1778 
1779     if (!CommonDeviceExtension->IsBus)
1780     {
1781         /* getting pnp device object is only supported for software bus device object */
1782        return STATUS_INVALID_PARAMETER;
1783     }
1784 
1785     /* sanity checks */
1786     ASSERT(CommonDeviceExtension);
1787     ASSERT(CommonDeviceExtension->IsBus);
1788 
1789     /* cast to bus device extension */
1790     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)CommonDeviceExtension;
1791 
1792     /* store result */
1793     *PnpDeviceObject = BusDeviceExtension->PnpDeviceObject;
1794 
1795     /* done */
1796     return STATUS_SUCCESS;
1797 }
1798 
1799 /*
1800     @implemented
1801 */
1802 KSDDKAPI
1803 NTSTATUS
1804 NTAPI
1805 KsInstallBusEnumInterface(
1806     PIRP Irp)
1807 {
1808     BUS_INSTALL_ENUM_CONTEXT Context;
1809     KPROCESSOR_MODE Mode;
1810     LUID luid;
1811     PIO_STACK_LOCATION IoStack;
1812     PDEV_EXTENSION DeviceExtension;
1813     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1814 
1815     DPRINT("KsInstallBusEnumInterface\n");
1816 
1817     /* get current irp stack location */
1818     IoStack = IoGetCurrentIrpStackLocation(Irp);
1819 
1820     /* get previous mode */
1821     Mode = ExGetPreviousMode();
1822 
1823     /* convert to luid */
1824     luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
1825 
1826     /* perform access check */
1827     if (!SeSinglePrivilegeCheck(luid, Mode))
1828     {
1829         /* FIXME insufficient privileges */
1830         //return STATUS_PRIVILEGE_NOT_HELD;
1831     }
1832 
1833     /* get device extension */
1834     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1835 
1836     /* get bus device extension */
1837     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1838 
1839 
1840     /* initialize context */
1841     Context.Irp = Irp;
1842     KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
1843     Context.BusDeviceExtension = BusDeviceExtension;
1844     ExInitializeWorkItem(&Context.WorkItem, KspInstallBusEnumInterface, (PVOID)&Context);
1845 
1846     /* queue the work item */
1847     ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
1848     /* wait for completion */
1849     KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
1850 
1851     /* store result */
1852     Irp->IoStatus.Status = Context.Status;
1853 
1854     /* done */
1855     return Context.Status;
1856 }
1857 
1858 /*
1859     @implemented
1860 */
1861 KSDDKAPI
1862 NTSTATUS
1863 NTAPI
1864 KsIsBusEnumChildDevice(
1865     IN PDEVICE_OBJECT DeviceObject,
1866     OUT PBOOLEAN ChildDevice)
1867 {
1868     PDEV_EXTENSION DeviceExtension;
1869     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1870 
1871     DPRINT("KsIsBusEnumChildDevice %p\n", DeviceObject);
1872 
1873     /* get device extension */
1874     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1875 
1876     /* get bus device extension */
1877     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1878 
1879     if (!BusDeviceExtension)
1880     {
1881         /* not a bus device */
1882         return STATUS_INVALID_PARAMETER;
1883     }
1884 
1885     /* store result */
1886     *ChildDevice = (BusDeviceExtension->Common.IsBus == FALSE);
1887 
1888     return STATUS_SUCCESS;
1889 }
1890 
1891 /*
1892     @implemented
1893 */
1894 KSDDKAPI
1895 NTSTATUS
1896 NTAPI
1897 KsServiceBusEnumCreateRequest(
1898     IN PDEVICE_OBJECT DeviceObject,
1899     IN OUT PIRP Irp)
1900 {
1901     PLIST_ENTRY Entry;
1902     PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* fix gcc */
1903     PIO_STACK_LOCATION IoStack;
1904     BOOLEAN ItemExists = FALSE;
1905     PDEV_EXTENSION DeviceExtension;
1906     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1907     //PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
1908     NTSTATUS Status;
1909     LARGE_INTEGER Time;
1910 
1911     /* FIXME: locks */
1912 
1913     /* get device extension */
1914     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1915 
1916     /* get bus device extension */
1917     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1918 
1919     /* get current irp stack location */
1920     IoStack = IoGetCurrentIrpStackLocation(Irp);
1921 
1922     /* sanity checks */
1923     ASSERT(IoStack->FileObject);
1924     if (IoStack->FileObject->FileName.Buffer == NULL)
1925     {
1926          DPRINT("KsServiceBusEnumCreateRequest PNP Hack\n");
1927          Irp->IoStatus.Status = STATUS_SUCCESS;
1928          return STATUS_SUCCESS;
1929     }
1930 
1931     ASSERT(IoStack->FileObject->FileName.Buffer);
1932 
1933     DPRINT1("KsServiceBusEnumCreateRequest IRP %p Name %wZ\n", Irp, &IoStack->FileObject->FileName);
1934 
1935     /* scan list and check if it is already present */
1936     Entry = BusDeviceExtension->Common.Entry.Flink;
1937 
1938     while(Entry != &BusDeviceExtension->Common.Entry)
1939     {
1940         /* get real offset */
1941         DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1942 
1943         /* check if name matches */
1944         if (!_wcsicmp(DeviceEntry->DeviceName, IoStack->FileObject->FileName.Buffer + 1))
1945         {
1946             /* item already exists */
1947             ItemExists = TRUE;
1948             break;
1949         }
1950 
1951         /* move to next entry */
1952         Entry = Entry->Flink;
1953     }
1954 
1955     if (!ItemExists)
1956     {
1957         /* interface not registered */
1958         DPRINT1("Interface %wZ not registered\n", &IoStack->FileObject->FileName);
1959         return STATUS_OBJECT_NAME_NOT_FOUND;
1960     }
1961 
1962     /*  is there a pdo yet */
1963     if (DeviceEntry->PDO)
1964     {
1965         if (DeviceEntry->DeviceState == Started)
1966         {
1967             /* issue reparse */
1968             Status =  KspDoReparseForIrp(Irp, DeviceEntry);
1969             DPRINT("REPARSE Irp %p '%wZ'\n", Irp, &IoStack->FileObject->FileName);
1970 
1971             Irp->IoStatus.Status = Status;
1972             Irp->IoStatus.Information = IO_REPARSE;
1973             return Status;
1974         }
1975 
1976         /* delay processing until pnp is finished with enumeration */
1977         IoMarkIrpPending(Irp);
1978 
1979         /* insert into irp pending list */
1980         InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
1981 
1982         Time.QuadPart = Int32x32To64(1500, -10000);
1983         DbgPrint("PENDING Irp %p %wZ DeviceState %d\n", Irp, &IoStack->FileObject->FileName, DeviceEntry->DeviceState);
1984 
1985 
1986         /* set timer */
1987         KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1988 
1989         /* done for now */
1990         return STATUS_PENDING;
1991 
1992     }
1993     else
1994     {
1995         /* time to create PDO */
1996         Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1997 
1998         if (!NT_SUCCESS(Status))
1999         {
2000             /* failed to create PDO */
2001             DPRINT1("KsServiceBusEnumCreateRequest failed to create PDO with %x\n", Status);
2002             return Status;
2003         }
2004         DPRINT("PENDING CREATE Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
2005 
2006         /* delay processing until pnp is finished with enumeration */
2007         IoMarkIrpPending(Irp);
2008 
2009         /* insert into irp pending list */
2010         InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
2011 
2012         /* invalidate device relations */
2013         IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
2014 
2015         /* done for now */
2016         return STATUS_PENDING;
2017     }
2018 }
2019 
2020 /*
2021     @implemented
2022 */
2023 KSDDKAPI
2024 NTSTATUS
2025 NTAPI
2026 KsServiceBusEnumPnpRequest(
2027     IN PDEVICE_OBJECT DeviceObject,
2028     IN OUT PIRP Irp)
2029 {
2030     PDEV_EXTENSION DeviceExtension;
2031     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
2032     PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
2033     PIO_STACK_LOCATION IoStack;
2034     NTSTATUS Status;
2035     LARGE_INTEGER Time;
2036     PDEVICE_RELATIONS DeviceRelation;
2037     PBUS_DEVICE_ENTRY DeviceEntry;
2038 
2039     /* get device extension */
2040     DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
2041 
2042     /* get bus device extension */
2043     BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
2044 
2045     /* get current irp stack location */
2046     IoStack = IoGetCurrentIrpStackLocation(Irp);
2047 
2048     if (BusDeviceExtension->Common.IsBus)
2049     {
2050         if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
2051         {
2052             /* no op for bus driver */
2053             Status = STATUS_SUCCESS;
2054         }
2055         else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
2056         {
2057             /* handle bus device relations */
2058             ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == BusRelations);
2059 
2060             Status = KspQueryBusRelations(BusDeviceExtension, Irp);
2061         }
2062         else
2063         {
2064             /* get default status */
2065             Status = Irp->IoStatus.Status;
2066         }
2067     }
2068     else
2069     {
2070         /* get child device extension */
2071         ChildDeviceExtension = DeviceExtension->Ext;
2072 
2073         /* get bus device extension */
2074         BusDeviceExtension = ChildDeviceExtension->BusDeviceExtension;
2075 
2076         if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
2077         {
2078             /* query id */
2079             Status = KspQueryId(ChildDeviceExtension, Irp);
2080         }
2081         else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
2082         {
2083             ASSERT(ChildDeviceExtension->DeviceEntry->DeviceState != Started || ChildDeviceExtension->DeviceEntry->DeviceState == NotStarted);
2084             ASSERT(ChildDeviceExtension->DeviceEntry->PDO == DeviceObject);
2085 
2086             /* backup device entry */
2087             DeviceEntry = ChildDeviceExtension->DeviceEntry;
2088 
2089             /* free device extension */
2090             FreeItem(ChildDeviceExtension);
2091 
2092             /* clear PDO reference */
2093             DeviceEntry->PDO = NULL;
2094 
2095             /* delete the device */
2096             IoDeleteDevice(DeviceObject);
2097 
2098             if (DeviceEntry->PDODeviceName)
2099             {
2100                 /* delete pdo device name */
2101                 FreeItem(DeviceEntry->PDODeviceName);
2102 
2103                 /* set to null */
2104                 DeviceEntry->PDODeviceName = NULL;
2105             }
2106 
2107             /* set state no notstarted */
2108             DeviceEntry->DeviceState = NotStarted;
2109 
2110             /* complete pending irps */
2111             KspCompletePendingIrps(DeviceEntry, STATUS_DEVICE_REMOVED);
2112 
2113             /* done */
2114             Status = STATUS_SUCCESS;
2115         }
2116         else if (IoStack->MinorFunction == IRP_MN_QUERY_BUS_INFORMATION)
2117         {
2118             /* query bus information */
2119             Status = KspQueryBusInformation(ChildDeviceExtension, Irp);
2120         }
2121         else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES)
2122         {
2123             /* no op */
2124             Status = STATUS_SUCCESS;
2125         }
2126         else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
2127         {
2128             /* no op */
2129             Status = STATUS_SUCCESS;
2130         }
2131         else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
2132         {
2133             /* start bus */
2134             Status = KspStartBusDevice(DeviceObject, ChildDeviceExtension, Irp);
2135             if (NT_SUCCESS(Status))
2136             {
2137                 /* complete pending irps*/
2138                 KspCompletePendingIrps(ChildDeviceExtension->DeviceEntry, STATUS_REPARSE);
2139             }
2140 
2141             /* set time out */
2142             Time.QuadPart = Int32x32To64(1500, -10000);
2143 
2144             /* sanity check */
2145             ASSERT(BusDeviceExtension);
2146 
2147             /* set timer */
2148             KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
2149         }
2150         else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES)
2151         {
2152             /* query capabilities */
2153             Status = KspQueryBusDeviceCapabilities(ChildDeviceExtension, Irp);
2154         }
2155         else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
2156         {
2157             /* query pnp state */
2158             Status = KspQueryBusDevicePnpState(ChildDeviceExtension, Irp);
2159         }
2160         else if (IoStack->MinorFunction == IRP_MN_QUERY_INTERFACE)
2161         {
2162             /* query interface */
2163             Status = KspQueryBusDeviceInterface(ChildDeviceExtension, Irp);
2164         }
2165         else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS && IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
2166         {
2167             /* handle target device relations */
2168             ASSERT(Irp->IoStatus.Information == 0);
2169 
2170             /* allocate device relation */
2171             DeviceRelation = AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
2172             if (DeviceRelation)
2173             {
2174                 DeviceRelation->Count = 1;
2175                 DeviceRelation->Objects[0] = DeviceObject;
2176 
2177                 /* reference self */
2178                 ObReferenceObject(DeviceObject);
2179 
2180                 /* store result */
2181                 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
2182 
2183                 /* done */
2184                 Status = STATUS_SUCCESS;
2185             }
2186             else
2187             {
2188                 /* no memory */
2189                 Status = STATUS_INSUFFICIENT_RESOURCES;
2190             }
2191         }
2192         else
2193         {
2194             /* get default status */
2195             Status = Irp->IoStatus.Status;
2196         }
2197     }
2198 
2199     DPRINT("KsServiceBusEnumPnpRequest %p Bus %u Function %x Status %x\n", DeviceObject, BusDeviceExtension->Common.IsBus, IoStack->MinorFunction, Status);
2200     Irp->IoStatus.Status = Status;
2201     return Status;
2202 }
2203 
2204 /*
2205     @implemented
2206 */
2207 KSDDKAPI
2208 NTSTATUS
2209 NTAPI
2210 KsRemoveBusEnumInterface(
2211     IN PIRP Irp)
2212 {
2213     KPROCESSOR_MODE Mode;
2214     LUID luid;
2215     BUS_INSTALL_ENUM_CONTEXT Ctx;
2216     PDEV_EXTENSION DeviceExtension;
2217     PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
2218     PIO_STACK_LOCATION IoStack;
2219 
2220     DPRINT("KsRemoveBusEnumInterface\n");
2221 
2222     /* get io stack location */
2223     IoStack = IoGetCurrentIrpStackLocation(Irp);
2224 
2225     /* get device extension */
2226     DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
2227 
2228     /* get bus device extension */
2229     BusDeviceExtension = DeviceExtension->Ext->BusDeviceExtension;
2230 
2231     /* get previous mode */
2232     Mode = ExGetPreviousMode();
2233 
2234     /* convert to luid */
2235     luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
2236 
2237     /* perform access check */
2238     if (!SeSinglePrivilegeCheck(luid, Mode))
2239     {
2240         /* insufficient privileges */
2241         return STATUS_PRIVILEGE_NOT_HELD;
2242     }
2243 
2244     /* initialize context */
2245     KeInitializeEvent(&Ctx.Event, NotificationEvent, FALSE);
2246     Ctx.Irp = Irp;
2247     Ctx.BusDeviceExtension = BusDeviceExtension;
2248     ExInitializeWorkItem(&Ctx.WorkItem, KspRemoveBusInterface, (PVOID)&Ctx);
2249 
2250     /* now queue the work item */
2251     ExQueueWorkItem(&Ctx.WorkItem, DelayedWorkQueue);
2252 
2253     /* wait for completion */
2254     KeWaitForSingleObject(&Ctx.Event, Executive, KernelMode, FALSE, NULL);
2255 
2256     /* return result */
2257     return Ctx.Status;
2258 }
2259