xref: /reactos/drivers/ksfilter/ks/swenum.c (revision e4930be4)
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
KspCreatePDO(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DeviceEntry,OUT PDEVICE_OBJECT * OutDeviceObject)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
KspRegisterDeviceAssociation(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DeviceEntry,IN OUT PBUS_INSTANCE_ENTRY BusInstanceEntry)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
KspRemoveDeviceAssociations(IN PBUS_DEVICE_ENTRY DeviceEntry)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
KspEnumerateBusRegistryKeys(IN HANDLE hKey,IN LPWSTR ReferenceString,IN PKSP_BUS_ENUM_CALLBACK Callback,IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DeviceEntry)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
KspCreateDeviceAssociation(IN PHANDLE hKey,IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DeviceEntry,IN LPWSTR InterfaceString,IN LPWSTR ReferenceString)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
KspCreateDeviceReference(IN PHANDLE hKey,IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DummyEntry,IN LPWSTR InterfaceId,IN LPWSTR DeviceId)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
KspCreateDeviceReferenceTrampoline(IN PHANDLE hKey,IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PBUS_DEVICE_ENTRY DummyEntry,IN LPWSTR DeviceCategory,IN LPWSTR ReferenceString)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
KspOpenBusRegistryKey(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,OUT PHANDLE hKey)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
KspScanBus(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension)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
KspBusQueryReferenceString(IN PVOID Context,IN OUT PWCHAR * String)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
KspBusDeviceReference(IN PVOID Context)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
KspBusDeviceDereference(IN PVOID Context)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
KspBusReferenceDeviceObject(IN PVOID Context)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
KspBusDereferenceDeviceObject(IN PVOID Context)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
KspQueryBusDeviceInterface(IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspEnableBusDeviceInterface(PBUS_DEVICE_ENTRY DeviceEntry,BOOLEAN bEnable)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
KspDoReparseForIrp(PIRP Irp,PBUS_DEVICE_ENTRY DeviceEntry)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
KspCompletePendingIrps(IN PBUS_DEVICE_ENTRY DeviceEntry,IN OUT NTSTATUS ResultCode)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
KspStartBusDevice(IN PDEVICE_OBJECT DeviceObject,IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspQueryBusDeviceCapabilities(IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspQueryBusInformation(IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspQueryBusDevicePnpState(IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspQueryId(IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,IN PIRP Irp)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
KspInstallInterface(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PSWENUM_INSTALL_INTERFACE InstallInterface)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
KspInstallBusEnumInterface(IN PVOID Ctx)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
KspBusWorkerRoutine(IN PVOID Parameter)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
KspBusDpcRoutine(IN PKDPC Dpc,IN PVOID DeferredContext OPTIONAL,IN PVOID SystemArgument1 OPTIONAL,IN PVOID SystemArgument2 OPTIONAL)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
KspRemoveBusInterface(PVOID Ctx)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
KspQueryBusRelations(IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,IN PIRP Irp)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
KsGetBusEnumIdentifier(IN PIRP Irp)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
KsGetBusEnumParentFDOFromChildPDO(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_OBJECT * FunctionalDeviceObject)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
KsCreateBusEnumObject(IN PWCHAR BusIdentifier,IN PDEVICE_OBJECT BusDeviceObject,IN PDEVICE_OBJECT PhysicalDeviceObject,IN PDEVICE_OBJECT PnpDeviceObject OPTIONAL,IN REFGUID InterfaceGuid OPTIONAL,IN PWCHAR ServiceRelativePath OPTIONAL)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
KsGetBusEnumPnpDeviceObject(IN PDEVICE_OBJECT DeviceObject,IN PDEVICE_OBJECT * PnpDeviceObject)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
KsInstallBusEnumInterface(PIRP Irp)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
KsIsBusEnumChildDevice(IN PDEVICE_OBJECT DeviceObject,OUT PBOOLEAN ChildDevice)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
KsServiceBusEnumCreateRequest(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)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
KsServiceBusEnumPnpRequest(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)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
KsRemoveBusEnumInterface(IN PIRP Irp)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