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