[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 "precomp.h"
10
11 #include <stdio.h>
12 #include <swenum.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 LONG KsDeviceCount = 0;
18
19 typedef NTSTATUS (NTAPI *PKSP_BUS_ENUM_CALLBACK)(
20 IN PHANDLE hKey,
21 IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
22 IN PBUS_DEVICE_ENTRY DummyEntry,
23 IN LPWSTR RootName,
24 IN LPWSTR DirectoryName);
25
26 NTSTATUS
27 KspCreatePDO(
28 IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
29 IN PBUS_DEVICE_ENTRY DeviceEntry,
30 OUT PDEVICE_OBJECT * OutDeviceObject)
31 {
32 PDEVICE_OBJECT DeviceObject;
33 WCHAR Buffer[50];
34 ULONG CurDeviceId;
35 UNICODE_STRING DeviceName;
36 NTSTATUS Status;
37 PCOMMON_DEVICE_EXTENSION DeviceExtension;
38
39 /* increment device count */
40 CurDeviceId = InterlockedIncrement(&KsDeviceCount);
41
42 /* generate new device id */
43 swprintf(Buffer, L"\\Device\\KSENUM%08x", CurDeviceId);
44
45 /* initialize new device name */
46 RtlInitUnicodeString(&DeviceName, Buffer);
47
48 /* create new device object */
49 Status = IoCreateDevice(BusDeviceExtension->BusDeviceObject->DriverObject, sizeof(PVOID), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);
50
51 /* check for success */
52 if (!NT_SUCCESS(Status))
53 {
54 /* failed to create pdo */
55 return Status;
56 }
57
58 /* now allocate device extension */
59 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)AllocateItem(NonPagedPool, sizeof(COMMON_DEVICE_EXTENSION));
60 if (!DeviceExtension)
61 {
62 /* no memory */
63 IoDeleteDevice(DeviceObject);
64 return STATUS_INSUFFICIENT_RESOURCES;
65 }
66
67 /* store device extension */
68 *((PVOID*)DeviceObject->DeviceExtension) = DeviceExtension;
69
70 /* initialize device extension */
71 DeviceExtension->IsBus = FALSE;
72 DeviceExtension->DeviceObject = DeviceObject;
73 DeviceExtension->DeviceEntry = DeviceEntry;
74 DeviceExtension->BusDeviceExtension = BusDeviceExtension;
75
76 /* 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 SIZE_T 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 SIZE_T 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 SIZE_T 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 ULONG NameLength;
761 PBUS_DEVICE_ENTRY DeviceEntry;
762
763 /* FIXME handle pending remove */
764
765 /* get full device name */
766 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyPhysicalDeviceObjectName, sizeof(PDOName), PDOName, &ResultLength);
767
768 if (!NT_SUCCESS(Status))
769 {
770 /* failed to get device name */
771 return Status;
772 }
773
774 /* allocate device name buffer */
775 NameLength = ResultLength + sizeof(UNICODE_NULL);
776 Name = AllocateItem(NonPagedPool, NameLength);
777 if (!Name)
778 {
779 /* no memory */
780 return STATUS_INSUFFICIENT_RESOURCES;
781 }
782
783 /* copy name */
784 NT_VERIFY(NT_SUCCESS(RtlStringCbCopyW(Name, NameLength, PDOName)));
785
786 /* TODO: time stamp creation time */
787
788 /* get device entry */
789 DeviceEntry = (PBUS_DEVICE_ENTRY)ChildDeviceExtension->DeviceEntry;
790
791 /* sanity check */
792 ASSERT(DeviceEntry);
793
794 /* store device name */
795 DeviceEntry->PDODeviceName = Name;
796
797 /* mark device as started */
798 DeviceEntry->DeviceState = Started;
799
800 /* reference start time */
801 KeQuerySystemTime(&DeviceEntry->TimeCreated);
802
803 DPRINT1("KspStartBusDevice Name %S DeviceName %S Instance %S Started\n", Name, DeviceEntry->DeviceName, DeviceEntry->Instance);
804
805 /* enable device classes */
806 //KspEnableBusDeviceInterface(DeviceEntry, TRUE);
807
808 /* done */
809 return STATUS_SUCCESS;
810 }
811
812 NTSTATUS
813 KspQueryBusDeviceCapabilities(
814 IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
815 IN PIRP Irp)
816 {
817 PDEVICE_CAPABILITIES Capabilities;
818 PIO_STACK_LOCATION IoStack;
819
820 /* get stack location */
821 IoStack = IoGetCurrentIrpStackLocation(Irp);
822
823 /* get capabilities */
824 Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
825
826 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
827
828 /* setup capabilities */
829 Capabilities->UniqueID = TRUE;
830 Capabilities->SilentInstall = TRUE;
831 Capabilities->SurpriseRemovalOK = TRUE;
832 Capabilities->Address = 0;
833 Capabilities->UINumber = 0;
834 Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
835 Capabilities->DeviceWake = PowerDeviceD0;
836
837 /* done */
838 return STATUS_SUCCESS;
839 }
840
841 NTSTATUS
842 KspQueryBusInformation(
843 IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
844 IN PIRP Irp)
845 {
846 PPNP_BUS_INFORMATION BusInformation;
847
848 /* allocate bus information */
849 BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
850
851 if (!BusInformation)
852 {
853 /* no memory */
854 return STATUS_INSUFFICIENT_RESOURCES;
855 }
856
857 /* return info */
858 BusInformation->BusNumber = 0;
859 BusInformation->LegacyBusType = InterfaceTypeUndefined;
860 RtlMoveMemory(&BusInformation->BusTypeGuid, &KSMEDIUMSETID_Standard, sizeof(GUID));
861
862 /* store result */
863 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
864
865 /* done */
866 return STATUS_SUCCESS;
867 }
868
869 NTSTATUS
870 KspQueryBusDevicePnpState(
871 IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
872 IN PIRP Irp)
873 {
874 /* set device flags */
875 Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
876
877 /* done */
878 return STATUS_SUCCESS;
879 }
880
881 NTSTATUS
882 KspQueryId(
883 IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
884 IN PIRP Irp)
885 {
886 PIO_STACK_LOCATION IoStack;
887 PBUS_DEVICE_ENTRY DeviceEntry;
888 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
889 LPWSTR Name;
890 SIZE_T Length;
891
892 /* get current irp stack location */
893 IoStack = IoGetCurrentIrpStackLocation(Irp);
894
895 if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
896 {
897 /* get device entry */
898 DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
899
900 /* sanity check */
901 ASSERT(DeviceEntry);
902 ASSERT(DeviceEntry->Instance);
903
904 /* calculate length */
905 Length = wcslen(DeviceEntry->Instance) + 1;
906
907 /* allocate buffer */
908 Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
909
910 if (!Name)
911 {
912 /* failed to allocate buffer */
913 return STATUS_INSUFFICIENT_RESOURCES;
914 }
915
916 /* copy buffer */
917 wcscpy(Name, DeviceEntry->Instance);
918
919 /* store result */
920 Irp->IoStatus.Information = (ULONG_PTR)Name;
921
922 /* done */
923 return STATUS_SUCCESS;
924 }
925 else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
926 IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
927 {
928 /* get device entry */
929 DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
930
931 /* get bus device extension */
932 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION) ChildDeviceExtension->BusDeviceExtension;
933
934 /* sanity check */
935 ASSERT(DeviceEntry);
936 ASSERT(DeviceEntry->BusId);
937 ASSERT(BusDeviceExtension);
938 ASSERT(BusDeviceExtension->BusIdentifier);
939
940 /* calculate length */
941 Length = wcslen(BusDeviceExtension->BusIdentifier);
942 Length += wcslen(DeviceEntry->BusId);
943
944 /* extra length for '\\' and zero byte */
945 Length += 2;
946
947 /* allocate buffer */
948 Name = ExAllocatePool(PagedPool, Length * sizeof(WCHAR));
949 if (!Name)
950 {
951 /* failed to allocate buffer */
952 return STATUS_INSUFFICIENT_RESOURCES;
953 }
954
955 /* construct id */
956 swprintf(Name, L"%s\\%s", BusDeviceExtension->BusIdentifier, DeviceEntry->BusId);
957
958 /* store result */
959 Irp->IoStatus.Information = (ULONG_PTR)Name;
960
961 /* done */
962 return STATUS_SUCCESS;
963 }
964 else
965 {
966 /* other ids are not supported */
967 //DPRINT1("Not Supported ID Type %x\n", IoStack->Parameters.QueryId.IdType);
968 return Irp->IoStatus.Status;
969 }
970 }
971
972 NTSTATUS
973 KspInstallInterface(
974 IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
975 IN PSWENUM_INSTALL_INTERFACE InstallInterface)
976 {
977 SIZE_T Length, Index;
978 UNICODE_STRING DeviceString, InterfaceString, ReferenceString;
979 HANDLE hKey, hDeviceKey, hInterfaceKey, hReferenceKey;
980 NTSTATUS Status;
981 OBJECT_ATTRIBUTES ObjectAttributes;
982
983 /* sanity check */
984 ASSERT(InstallInterface);
985
986 /* calculate length */
987 Length = wcslen(InstallInterface->ReferenceString);
988
989 /* check for invalid characters */
990 for(Index = 0; Index < Length; Index++)
991 {
992 if (InstallInterface->ReferenceString[Index] <= L' ' ||
993 InstallInterface->ReferenceString[Index] > L'~' ||
994 InstallInterface->ReferenceString[Index] == L',' ||
995 InstallInterface->ReferenceString[Index] == L'\\' ||
996 InstallInterface->ReferenceString[Index] == L'/')
997 {
998 /* invalid character */
999 return STATUS_INVALID_PARAMETER;
1000 }
1001 }
1002
1003 /* open bus key */
1004 Status = KspOpenBusRegistryKey(BusDeviceExtension, &hKey);
1005 if (NT_SUCCESS(Status))
1006 {
1007 /* convert device guid to string */
1008 Status = RtlStringFromGUID(&InstallInterface->DeviceId, &DeviceString);
1009 if (NT_SUCCESS(Status))
1010 {
1011 /* initialize object attributes */
1012 InitializeObjectAttributes(&ObjectAttributes, &DeviceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hKey, NULL);
1013
1014 /* construct device key */
1015 Status = ZwCreateKey(&hDeviceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1016 if (NT_SUCCESS(Status))
1017 {
1018 /* initialize reference string */
1019 RtlInitUnicodeString(&ReferenceString, InstallInterface->ReferenceString);
1020
1021 /* initialize object attributes */
1022 InitializeObjectAttributes(&ObjectAttributes, &ReferenceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceKey, NULL);
1023
1024 /* construct device key */
1025 Status = ZwCreateKey(&hReferenceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1026 if (NT_SUCCESS(Status))
1027 {
1028 /* convert interface guid to string */
1029 Status = RtlStringFromGUID(&InstallInterface->InterfaceId, &InterfaceString);
1030 if (NT_SUCCESS(Status))
1031 {
1032 /* initialize object attributes */
1033 InitializeObjectAttributes(&ObjectAttributes, &InterfaceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hReferenceKey, NULL);
1034
1035 /* construct device key */
1036 Status = ZwCreateKey(&hInterfaceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1037 if (NT_SUCCESS(Status))
1038 {
1039 /* close key */
1040 ZwClose(hInterfaceKey);
1041 }
1042 /* free interface string */
1043 RtlFreeUnicodeString(&InterfaceString);
1044 }
1045 /* close reference key */
1046 ZwClose(hReferenceKey);
1047 }
1048 /* close device key */
1049 ZwClose(hDeviceKey);
1050 }
1051 /* free device string */
1052 RtlFreeUnicodeString(&DeviceString);
1053 }
1054 /* close bus key */
1055 ZwClose(hKey);
1056 }
1057
1058 /* done */
1059 return Status;
1060 }
1061
1062 VOID
1063 NTAPI
1064 KspInstallBusEnumInterface(
1065 IN PVOID Ctx)
1066 {
1067 PIO_STACK_LOCATION IoStack;
1068 NTSTATUS Status;
1069 PLIST_ENTRY Entry;
1070 PBUS_DEVICE_ENTRY DeviceEntry;
1071 PSWENUM_INSTALL_INTERFACE InstallInterface;
1072 KIRQL OldLevel;
1073 PBUS_INSTALL_ENUM_CONTEXT Context = (PBUS_INSTALL_ENUM_CONTEXT)Ctx;
1074
1075 /* get current irp stack location */
1076 IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
1077
1078 /* get install request */
1079 InstallInterface = (PSWENUM_INSTALL_INTERFACE)Context->Irp->AssociatedIrp.SystemBuffer;
1080
1081 /* sanity check */
1082 ASSERT(InstallInterface);
1083 ASSERT(Context->BusDeviceExtension);
1084
1085 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SWENUM_INSTALL_INTERFACE))
1086 {
1087 /* buffer too small */
1088 Context->Status = STATUS_INVALID_PARAMETER;
1089
1090 /* signal completion */
1091 KeSetEvent(&Context->Event, 0, FALSE);
1092
1093 /* done */
1094 return;
1095 }
1096
1097 /* FIXME locks */
1098
1099 /* now install the interface */
1100 Status = KspInstallInterface(Context->BusDeviceExtension, InstallInterface);
1101 if (!NT_SUCCESS(Status))
1102 {
1103 /* failed to install interface */
1104 Context->Status = Status;
1105
1106 /* signal completion */
1107 KeSetEvent(&Context->Event, 0, FALSE);
1108
1109 /* done */
1110 return;
1111 }
1112
1113 /* acquire device entry lock */
1114 KeAcquireSpinLock(&Context->BusDeviceExtension->Lock, &OldLevel);
1115
1116 /* now iterate all device entries */
1117 Entry = Context->BusDeviceExtension->Common.Entry.Flink;
1118 while(Entry != &Context->BusDeviceExtension->Common.Entry)
1119 {
1120 /* get device entry */
1121 DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1122
1123 if (IsEqualGUIDAligned(&DeviceEntry->DeviceGuid, &InstallInterface->DeviceId) &&
1124 !wcsicmp(DeviceEntry->Instance, InstallInterface->ReferenceString))
1125 {
1126 if (!DeviceEntry->PDO)
1127 {
1128 /* create pdo */
1129 Status = KspCreatePDO(Context->BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1130
1131 /* done */
1132 break;
1133 }
1134 }
1135
1136 /* move to next entry */
1137 Entry = Entry->Flink;
1138 }
1139
1140 /* release device entry lock */
1141 KeReleaseSpinLock(&Context->BusDeviceExtension->Lock, OldLevel);
1142
1143 /* signal that bus driver relations has changed */
1144 IoInvalidateDeviceRelations(Context->BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1145
1146 /* update status */
1147 Context->Status = Status;
1148
1149 /* signal completion */
1150 KeSetEvent(&Context->Event, 0, FALSE);
1151 }
1152
1153
1154 VOID
1155 NTAPI
1156 KspBusWorkerRoutine(
1157 IN PVOID Parameter)
1158 {
1159 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1160 PBUS_DEVICE_ENTRY DeviceEntry;
1161 PLIST_ENTRY Entry;
1162 LARGE_INTEGER Time, Diff;
1163 BOOLEAN DoInvalidate = FALSE;
1164 KIRQL OldLevel;
1165
1166 /* get device extension */
1167 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)Parameter;
1168
1169 /* acquire lock */
1170 KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1171
1172 /* get current time */
1173 KeQuerySystemTime(&Time);
1174
1175 /* enumerate all device entries */
1176 Entry = BusDeviceExtension->Common.Entry.Flink;
1177 while(Entry != &BusDeviceExtension->Common.Entry)
1178 {
1179 /* get offset to device entry */
1180 DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1181
1182 /* sanity check */
1183 ASSERT(DeviceEntry);
1184
1185 //DPRINT1("DeviceEntry %p PDO %p State %x\n", DeviceEntry, DeviceEntry->PDO, DeviceEntry->DeviceState);
1186
1187 if (DeviceEntry->PDO)
1188 {
1189 if (DeviceEntry->DeviceState == NotStarted)
1190 {
1191 Diff.QuadPart = Time.QuadPart - DeviceEntry->TimeCreated.QuadPart;
1192
1193 if (Diff.QuadPart > Int32x32To64(15000, 10000))
1194 {
1195 DPRINT1("DeviceID %S Instance %S TimeCreated %I64u Now %I64u Diff %I64u hung\n", DeviceEntry->DeviceName, DeviceEntry->Instance, DeviceEntry->TimeCreated.QuadPart, Time.QuadPart, Diff.QuadPart);
1196
1197 /* release spin lock */
1198 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1199
1200 /* deactivate interfaces */
1201 //KspEnableBusDeviceInterface(DeviceEntry, FALSE);
1202
1203 /* re-acquire lock */
1204 KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1205
1206 /* pending remove device object */
1207 DeviceEntry->DeviceState = StopPending;
1208
1209 /* perform invalidation */
1210 DoInvalidate = TRUE;
1211 }
1212 }
1213 else if (DeviceEntry->DeviceState == Started)
1214 {
1215 /* found pending irps */
1216 KspCompletePendingIrps(DeviceEntry, STATUS_REPARSE);
1217 }
1218 }
1219
1220
1221 /* move to next */
1222 Entry = Entry->Flink;
1223 }
1224
1225 /* release lock */
1226 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1227
1228 if (DoInvalidate)
1229 {
1230 /* invalidate device relations */
1231 IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1232 }
1233
1234 Time.QuadPart = Int32x32To64(5000, -10000);
1235 KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1236 }
1237
1238 VOID
1239 NTAPI
1240 KspBusDpcRoutine(
1241 IN PKDPC Dpc,
1242 IN PVOID DeferredContext OPTIONAL,
1243 IN PVOID SystemArgument1 OPTIONAL,
1244 IN PVOID SystemArgument2 OPTIONAL)
1245 {
1246 /* get device extension */
1247 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeferredContext;
1248
1249 /* queue the item */
1250 ExQueueWorkItem(&BusDeviceExtension->WorkItem, DelayedWorkQueue);
1251 }
1252
1253 VOID
1254 NTAPI
1255 KspRemoveBusInterface(
1256 PVOID Ctx)
1257 {
1258 PBUS_INSTALL_ENUM_CONTEXT Context =(PBUS_INSTALL_ENUM_CONTEXT)Ctx;
1259
1260 /* TODO
1261 * get SWENUM_INSTALL_INTERFACE struct
1262 * open device key and delete the keys
1263 */
1264
1265 UNIMPLEMENTED
1266
1267 /* set status */
1268 Context->Status = STATUS_NOT_IMPLEMENTED;
1269
1270
1271 /* signal completion */
1272 KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
1273 }
1274
1275 NTSTATUS
1276 KspQueryBusRelations(
1277 IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
1278 IN PIRP Irp)
1279 {
1280 PDEVICE_RELATIONS DeviceRelations;
1281 PLIST_ENTRY Entry;
1282 PBUS_DEVICE_ENTRY DeviceEntry;
1283 ULONG Count = 0, Length;
1284 KIRQL OldLevel;
1285
1286 /* acquire lock */
1287 KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
1288
1289 /* first scan all device entries */
1290 Entry = BusDeviceExtension->Common.Entry.Flink;
1291
1292 while(Entry != &BusDeviceExtension->Common.Entry)
1293 {
1294 /* get offset to device entry */
1295 DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1296
1297 /* is there a pdo yet */
1298 if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1299 {
1300 /* increment count */
1301 Count++;
1302 }
1303
1304 /* move to next entry */
1305 Entry = Entry->Flink;
1306 }
1307
1308 /* calculate length */
1309 Length = sizeof(DEVICE_RELATIONS) + (Count > 1 ? sizeof(PDEVICE_OBJECT) * (Count-1) : 0);
1310
1311 /* allocate device relations */
1312 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, Length);
1313
1314 if (!DeviceRelations)
1315 {
1316 /* not enough memory */
1317 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1318 return STATUS_INSUFFICIENT_RESOURCES;
1319 }
1320
1321 /* rescan device entries */
1322 Entry = BusDeviceExtension->Common.Entry.Flink;
1323
1324 while(Entry != &BusDeviceExtension->Common.Entry)
1325 {
1326 /* get offset to device entry */
1327 DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1328
1329 /* is there a pdo yet */
1330 if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
1331 {
1332 /* store pdo */
1333 DeviceRelations->Objects[DeviceRelations->Count] = DeviceEntry->PDO;
1334
1335 /* reference device object */
1336 ObReferenceObject(DeviceEntry->PDO);
1337
1338 /* increment pdo count */
1339 DeviceRelations->Count++;
1340 }
1341
1342 /* move to next entry */
1343 Entry = Entry->Flink;
1344 }
1345
1346 /* release lock */
1347 KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
1348
1349 /* FIXME handle existing device relations */
1350 ASSERT(Irp->IoStatus.Information == 0);
1351
1352 /* store device relations */
1353 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1354
1355 /* done */
1356 return STATUS_SUCCESS;
1357 }
1358
1359 //------------------------------------------------------------------------------------
1360
1361 /*
1362 @implemented
1363 */
1364
1365 KSDDKAPI
1366 NTSTATUS
1367 NTAPI
1368 KsGetBusEnumIdentifier(
1369 IN PIRP Irp)
1370 {
1371 PDEV_EXTENSION DeviceExtension;
1372 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1373 PIO_STACK_LOCATION IoStack;
1374 SIZE_T Length;
1375 NTSTATUS Status;
1376 LPWSTR Buffer;
1377
1378 DPRINT1("KsGetBusEnumIdentifier\n");
1379
1380 /* get stack location */
1381 IoStack = IoGetCurrentIrpStackLocation(Irp);
1382
1383 /* sanity checks */
1384 ASSERT(IoStack->DeviceObject);
1385 ASSERT(IoStack->DeviceObject->DeviceExtension);
1386
1387 /* get device extension */
1388 DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1389
1390 /* get bus device extension */
1391 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1392
1393 /* sanity checks */
1394 ASSERT(BusDeviceExtension);
1395 ASSERT(BusDeviceExtension->Common.IsBus);
1396
1397 if (!BusDeviceExtension)
1398 {
1399 /* invalid parameter */
1400 return STATUS_INVALID_PARAMETER;
1401 }
1402
1403 /* get length */
1404 Length = (wcslen(BusDeviceExtension->BusIdentifier)+1) * sizeof(WCHAR);
1405
1406 /* is there an output buffer provided */
1407 if (IoStack->Parameters.DeviceIoControl.InputBufferLength)
1408 {
1409 if (Length > IoStack->Parameters.DeviceIoControl.InputBufferLength)
1410 {
1411 /* buffer is too small */
1412 return STATUS_BUFFER_TOO_SMALL;
1413 }
1414
1415 /* now allocate buffer */
1416 Buffer = AllocateItem(NonPagedPool, Length);
1417 if (!Buffer)
1418 {
1419 /* no memory */
1420 Status = STATUS_INSUFFICIENT_RESOURCES;
1421 }
1422 else
1423 {
1424 /* copy bus identifier */
1425 wcscpy(Buffer, BusDeviceExtension->BusIdentifier);
1426
1427 /* store buffer */
1428 Irp->AssociatedIrp.SystemBuffer = Buffer;
1429
1430 /* set flag that buffer gets copied back */
1431 Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
1432
1433 /* done */
1434 Status = STATUS_SUCCESS;
1435 }
1436 }
1437 else
1438 {
1439 /* no buffer provided */
1440 Status = STATUS_BUFFER_OVERFLOW;
1441 }
1442
1443 /* done */
1444 Irp->IoStatus.Status = Status;
1445 return Status;
1446 }
1447
1448 /*
1449 @implemented
1450 */
1451 KSDDKAPI
1452 NTSTATUS
1453 NTAPI
1454 KsGetBusEnumParentFDOFromChildPDO(
1455 IN PDEVICE_OBJECT DeviceObject,
1456 OUT PDEVICE_OBJECT *FunctionalDeviceObject)
1457 {
1458 PDEV_EXTENSION DeviceExtension;
1459
1460 DPRINT1("KsGetBusEnumParentFDOFromChildPDO\n");
1461
1462 /* get device extension */
1463 DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1464
1465 /* check if this is child pdo */
1466 if (DeviceExtension->Ext->IsBus == FALSE)
1467 {
1468 /* return bus device object */
1469 *FunctionalDeviceObject = DeviceExtension->Ext->BusDeviceExtension->BusDeviceObject;
1470
1471 /* done */
1472 return STATUS_SUCCESS;
1473 }
1474
1475 /* invalid parameter */
1476 return STATUS_INVALID_PARAMETER;
1477 }
1478
1479
1480 /*
1481 @implemented
1482 */
1483 KSDDKAPI
1484 NTSTATUS
1485 NTAPI
1486 KsCreateBusEnumObject(
1487 IN PWCHAR BusIdentifier,
1488 IN PDEVICE_OBJECT BusDeviceObject,
1489 IN PDEVICE_OBJECT PhysicalDeviceObject,
1490 IN PDEVICE_OBJECT PnpDeviceObject OPTIONAL,
1491 IN REFGUID InterfaceGuid OPTIONAL,
1492 IN PWCHAR ServiceRelativePath OPTIONAL)
1493 {
1494 SIZE_T Length;
1495 NTSTATUS Status = STATUS_SUCCESS;
1496 UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
1497 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1498 PDEV_EXTENSION DeviceExtension;
1499
1500 DPRINT1("KsCreateBusEnumObject %S BusDeviceObject %p\n", ServiceRelativePath, BusDeviceObject);
1501
1502 /* calculate sizeof bus enum device extension */
1503 Length = wcslen(BusIdentifier) * sizeof(WCHAR);
1504 Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
1505
1506 BusDeviceExtension = AllocateItem(NonPagedPool, Length);
1507 if (!BusDeviceExtension)
1508 {
1509 /* not enough memory */
1510
1511 return STATUS_INSUFFICIENT_RESOURCES;
1512 }
1513
1514 /* get device extension */
1515 DeviceExtension = (PDEV_EXTENSION)BusDeviceObject->DeviceExtension;
1516
1517 DPRINT1("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
1518
1519 /* store bus device extension */
1520 DeviceExtension->Ext = (PCOMMON_DEVICE_EXTENSION)BusDeviceExtension;
1521
1522 DPRINT1("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
1523
1524
1525 /* zero device extension */
1526 RtlZeroMemory(BusDeviceExtension, sizeof(BUS_ENUM_DEVICE_EXTENSION));
1527
1528 /* initialize bus device extension */
1529 wcscpy(BusDeviceExtension->BusIdentifier, BusIdentifier);
1530
1531 /* allocate service path string */
1532 Length = ServiceKeyPath.MaximumLength;
1533 Length += BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName.MaximumLength;
1534
1535 if (ServiceRelativePath)
1536 {
1537 /* relative path for devices */
1538 Length += (wcslen(ServiceRelativePath) + 2) * sizeof(WCHAR);
1539 }
1540
1541 BusDeviceExtension->ServicePath.Length = 0;
1542 BusDeviceExtension->ServicePath.MaximumLength = (USHORT)Length;
1543 BusDeviceExtension->ServicePath.Buffer = AllocateItem(NonPagedPool, Length);
1544
1545 if (!BusDeviceExtension->ServicePath.Buffer)
1546 {
1547 /* not enough memory */
1548 FreeItem(BusDeviceExtension);
1549
1550 return STATUS_INSUFFICIENT_RESOURCES;
1551 }
1552
1553 RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &ServiceKeyPath);
1554 RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName);
1555
1556 if (ServiceRelativePath)
1557 {
1558 RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, L"\\");
1559 RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, ServiceRelativePath);
1560 }
1561
1562 if (InterfaceGuid)
1563 {
1564 /* register an device interface */
1565 Status = IoRegisterDeviceInterface(PhysicalDeviceObject, InterfaceGuid, NULL, &BusDeviceExtension->DeviceInterfaceLink);
1566
1567 /* check for success */
1568 if (!NT_SUCCESS(Status))
1569 {
1570
1571 FreeItem(BusDeviceExtension->ServicePath.Buffer);
1572 FreeItem(BusDeviceExtension);
1573 return Status;
1574 }
1575
1576 /* now enable device interface */
1577 Status = IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, TRUE);
1578
1579 if (!NT_SUCCESS(Status))
1580 {
1581 FreeItem(BusDeviceExtension->ServicePath.Buffer);
1582 FreeItem(BusDeviceExtension);
1583 return Status;
1584 }
1585 }
1586
1587 /* initialize common device extension */
1588 BusDeviceExtension->Common.BusDeviceExtension = NULL;
1589 BusDeviceExtension->Common.DeviceObjectReferenceCount = 1;
1590 BusDeviceExtension->Common.DeviceReferenceCount = 1;
1591 BusDeviceExtension->Common.IsBus = TRUE;
1592 InitializeListHead(&BusDeviceExtension->Common.Entry);
1593
1594 /* store device objects */
1595 BusDeviceExtension->BusDeviceObject = BusDeviceObject;
1596 BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
1597
1598 /* initialize lock */
1599 KeInitializeSpinLock(&BusDeviceExtension->Lock);
1600
1601 /* initialize timer */
1602 KeInitializeTimer(&BusDeviceExtension->Timer);
1603
1604 /* initialize dpc */
1605 KeInitializeDpc(&BusDeviceExtension->Dpc, KspBusDpcRoutine, (PVOID)BusDeviceExtension);
1606
1607 /* initialize event */
1608 KeInitializeEvent(&BusDeviceExtension->Event, SynchronizationEvent, FALSE);
1609
1610 /* initialize work item */
1611 ExInitializeWorkItem(&BusDeviceExtension->WorkItem, KspBusWorkerRoutine, (PVOID)BusDeviceExtension);
1612
1613 if (!PnpDeviceObject)
1614 {
1615 /* attach device */
1616 BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
1617
1618 if (!BusDeviceExtension->PnpDeviceObject)
1619 {
1620 /* failed to attach device */
1621 if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1622 {
1623 IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1624 RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1625 }
1626
1627 /* free device extension */
1628 FreeItem(BusDeviceExtension->ServicePath.Buffer);
1629 FreeItem(BusDeviceExtension);
1630
1631 return STATUS_DEVICE_REMOVED;
1632 }
1633
1634 /* mark device as attached */
1635 BusDeviceExtension->DeviceAttached = TRUE;
1636 }
1637 else
1638 {
1639 /* directly attach */
1640 BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
1641 }
1642
1643 /* now scan the bus */
1644 Status = KspScanBus(BusDeviceExtension);
1645
1646 /* check for success */
1647 if (!NT_SUCCESS(Status))
1648 {
1649 /* failed to scan bus */
1650 if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
1651 {
1652 IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
1653 RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
1654 }
1655
1656 if (BusDeviceExtension->DeviceAttached)
1657 {
1658 /* detach device */
1659 IoDetachDevice(BusDeviceExtension->PnpDeviceObject);
1660 }
1661
1662 /* free device extension */
1663 FreeItem(BusDeviceExtension->ServicePath.Buffer);
1664 FreeItem(BusDeviceExtension);
1665 }
1666
1667 DPRINT("KsCreateBusEnumObject Status %x\n", Status);
1668 /* done */
1669 return Status;
1670 }
1671
1672 /*
1673 @implemented
1674 */
1675 KSDDKAPI
1676 NTSTATUS
1677 NTAPI
1678 KsGetBusEnumPnpDeviceObject(
1679 IN PDEVICE_OBJECT DeviceObject,
1680 IN PDEVICE_OBJECT *PnpDeviceObject)
1681 {
1682 PDEV_EXTENSION DeviceExtension;
1683 PCOMMON_DEVICE_EXTENSION CommonDeviceExtension;
1684 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1685
1686 DPRINT("KsGetBusEnumPnpDeviceObject\n");
1687
1688 if (!DeviceObject->DeviceExtension)
1689 {
1690 /* invalid parameter */
1691 return STATUS_INVALID_PARAMETER;
1692 }
1693
1694 /* get device extension */
1695 DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1696
1697 /* get common device extension */
1698 CommonDeviceExtension = DeviceExtension->Ext;
1699
1700 if (!CommonDeviceExtension)
1701 {
1702 /* invalid parameter */
1703 return STATUS_INVALID_PARAMETER;
1704 }
1705
1706 if (!CommonDeviceExtension->IsBus)
1707 {
1708 /* getting pnp device object is only supported for software bus device object */
1709 return STATUS_INVALID_PARAMETER;
1710 }
1711
1712 /* sanity checks */
1713 ASSERT(CommonDeviceExtension);
1714 ASSERT(CommonDeviceExtension->IsBus);
1715
1716 /* cast to bus device extension */
1717 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)CommonDeviceExtension;
1718
1719 /* store result */
1720 *PnpDeviceObject = BusDeviceExtension->PnpDeviceObject;
1721
1722 /* done */
1723 return STATUS_SUCCESS;
1724 }
1725
1726 /*
1727 @implemented
1728 */
1729 KSDDKAPI
1730 NTSTATUS
1731 NTAPI
1732 KsInstallBusEnumInterface(
1733 PIRP Irp)
1734 {
1735 BUS_INSTALL_ENUM_CONTEXT Context;
1736 KPROCESSOR_MODE Mode;
1737 LUID luid;
1738 PIO_STACK_LOCATION IoStack;
1739 PDEV_EXTENSION DeviceExtension;
1740 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1741
1742 DPRINT1("KsInstallBusEnumInterface\n");
1743
1744 /* get current irp stack location */
1745 IoStack = IoGetCurrentIrpStackLocation(Irp);
1746
1747 /* get previous mode */
1748 Mode = ExGetPreviousMode();
1749
1750 /* convert to luid */
1751 luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
1752
1753 /* perform access check */
1754 if (!SeSinglePrivilegeCheck(luid, Mode))
1755 {
1756 /* insufficient privileges */
1757 return STATUS_PRIVILEGE_NOT_HELD;
1758 }
1759
1760 /* get device extension */
1761 DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
1762
1763 /* get bus device extension */
1764 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1765
1766
1767 /* initialize context */
1768 Context.Irp = Irp;
1769 KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
1770 Context.BusDeviceExtension = BusDeviceExtension;
1771 ExInitializeWorkItem(&Context.WorkItem, KspInstallBusEnumInterface, (PVOID)&Context);
1772
1773 /* queue the work item */
1774 ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
1775 /* wait for completion */
1776 KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
1777
1778 /* store result */
1779 Irp->IoStatus.Status = Context.Status;
1780
1781 /* done */
1782 return Context.Status;
1783 }
1784
1785 /*
1786 @implemented
1787 */
1788 KSDDKAPI
1789 NTSTATUS
1790 NTAPI
1791 KsIsBusEnumChildDevice(
1792 IN PDEVICE_OBJECT DeviceObject,
1793 OUT PBOOLEAN ChildDevice)
1794 {
1795 PDEV_EXTENSION DeviceExtension;
1796 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1797
1798 DPRINT("KsIsBusEnumChildDevice %p\n", DeviceObject);
1799
1800 /* get device extension */
1801 DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1802
1803 /* get bus device extension */
1804 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1805
1806 if (!BusDeviceExtension)
1807 {
1808 /* not a bus device */
1809 return STATUS_INVALID_PARAMETER;
1810 }
1811
1812 /* store result */
1813 *ChildDevice = (BusDeviceExtension->Common.IsBus == FALSE);
1814
1815 return STATUS_SUCCESS;
1816 }
1817
1818 /*
1819 @implemented
1820 */
1821 KSDDKAPI
1822 NTSTATUS
1823 NTAPI
1824 KsServiceBusEnumCreateRequest(
1825 IN PDEVICE_OBJECT DeviceObject,
1826 IN OUT PIRP Irp)
1827 {
1828 PLIST_ENTRY Entry;
1829 PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* fix gcc */
1830 PIO_STACK_LOCATION IoStack;
1831 BOOLEAN ItemExists = FALSE;
1832 PDEV_EXTENSION DeviceExtension;
1833 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1834 //PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
1835 NTSTATUS Status;
1836 LARGE_INTEGER Time;
1837
1838 /* FIXME: locks */
1839
1840 /* get device extension */
1841 DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1842
1843 /* get bus device extension */
1844 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1845
1846 /* get current irp stack location */
1847 IoStack = IoGetCurrentIrpStackLocation(Irp);
1848
1849 /* sanity checks */
1850 ASSERT(IoStack->FileObject);
1851 ASSERT(IoStack->FileObject->FileName.Buffer);
1852
1853 DPRINT1("KsServiceBusEnumCreateRequest IRP %p Name %wZ\n", Irp, &IoStack->FileObject->FileName);
1854
1855 /* scan list and check if it is already present */
1856 Entry = BusDeviceExtension->Common.Entry.Flink;
1857
1858 while(Entry != &BusDeviceExtension->Common.Entry)
1859 {
1860 /* get real offset */
1861 DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
1862
1863 /* check if name matches */
1864 if (!wcsicmp(DeviceEntry->DeviceName, IoStack->FileObject->FileName.Buffer + 1))
1865 {
1866 /* item already exists */
1867 ItemExists = TRUE;
1868 break;
1869 }
1870
1871 /* move to next entry */
1872 Entry = Entry->Flink;
1873 }
1874
1875 if (!ItemExists)
1876 {
1877 /* interface not registered */
1878 DPRINT1("Interface %wZ not registered\n", &IoStack->FileObject->FileName);
1879 return STATUS_OBJECT_NAME_NOT_FOUND;
1880 }
1881
1882 /* is there a pdo yet */
1883 if (DeviceEntry->PDO)
1884 {
1885 if (DeviceEntry->DeviceState == Started)
1886 {
1887 /* issue reparse */
1888 Status = KspDoReparseForIrp(Irp, DeviceEntry);
1889 DPRINT("REPARSE Irp %p '%wZ'\n", Irp, &IoStack->FileObject->FileName);
1890
1891 Irp->IoStatus.Status = Status;
1892 return Status;
1893 }
1894
1895 /* delay processing until pnp is finished with enumeration */
1896 IoMarkIrpPending(Irp);
1897
1898 /* insert into irp pending list */
1899 InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
1900
1901 Time.QuadPart = Int32x32To64(1500, -10000);
1902 DbgPrint("PENDING Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
1903
1904 /* query current time */
1905 KeQuerySystemTime(&DeviceEntry->TimeCreated);
1906
1907 /* set timer */
1908 KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
1909
1910 /* done for now */
1911 return STATUS_PENDING;
1912
1913 }
1914 else
1915 {
1916 /* time to create PDO */
1917 Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
1918
1919 if (!NT_SUCCESS(Status))
1920 {
1921 /* failed to create PDO */
1922 DPRINT1("KsServiceBusEnumCreateRequest failed to create PDO with %x\n", Status);
1923 return Status;
1924 }
1925 DPRINT1("PENDING CREATE Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
1926
1927 /* delay processing until pnp is finished with enumeration */
1928 IoMarkIrpPending(Irp);
1929
1930 /* insert into irp pending list */
1931 InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
1932
1933 /* get current time */
1934 KeQuerySystemTime(&DeviceEntry->TimeCreated);
1935
1936 /* invalidate device relations */
1937 IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
1938
1939 /* done for now */
1940 return STATUS_PENDING;
1941 }
1942 }
1943
1944 /*
1945 @implemented
1946 */
1947 KSDDKAPI
1948 NTSTATUS
1949 NTAPI
1950 KsServiceBusEnumPnpRequest(
1951 IN PDEVICE_OBJECT DeviceObject,
1952 IN OUT PIRP Irp)
1953 {
1954 PDEV_EXTENSION DeviceExtension;
1955 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
1956 PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
1957 PIO_STACK_LOCATION IoStack;
1958 NTSTATUS Status;
1959 LARGE_INTEGER Time;
1960 PDEVICE_RELATIONS DeviceRelation;
1961 PBUS_DEVICE_ENTRY DeviceEntry;
1962
1963 /* get device extension */
1964 DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
1965
1966 /* get bus device extension */
1967 BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
1968
1969 /* get current irp stack location */
1970 IoStack = IoGetCurrentIrpStackLocation(Irp);
1971
1972 if (BusDeviceExtension->Common.IsBus)
1973 {
1974 if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
1975 {
1976 /* no op for bus driver */
1977 Status = STATUS_SUCCESS;
1978 }
1979 else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
1980 {
1981 /* handle bus device relations */
1982 ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == BusRelations);
1983
1984 Status = KspQueryBusRelations(BusDeviceExtension, Irp);
1985 }
1986 else
1987 {
1988 /* get default status */
1989 Status = Irp->IoStatus.Status;
1990 }
1991 }
1992 else
1993 {
1994 /* get child device extension */
1995 ChildDeviceExtension = DeviceExtension->Ext;
1996
1997 /* get bus device extension */
1998 BusDeviceExtension = ChildDeviceExtension->BusDeviceExtension;
1999
2000 if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
2001 {
2002 /* query id */
2003 Status = KspQueryId(ChildDeviceExtension, Irp);
2004 }
2005 else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
2006 {
2007 ASSERT(ChildDeviceExtension->DeviceEntry->DeviceState != Started || ChildDeviceExtension->DeviceEntry->DeviceState == NotStarted);
2008 ASSERT(ChildDeviceExtension->DeviceEntry->PDO == DeviceObject);
2009
2010 /* backup device entry */
2011 DeviceEntry = ChildDeviceExtension->DeviceEntry;
2012
2013 /* free device extension */
2014 FreeItem(ChildDeviceExtension);
2015
2016 /* clear PDO reference */
2017 DeviceEntry->PDO = NULL;
2018
2019 /* delete the device */
2020 IoDeleteDevice(DeviceObject);
2021
2022 if (DeviceEntry->PDODeviceName)
2023 {
2024 /* delete pdo device name */
2025 FreeItem(DeviceEntry->PDODeviceName);
2026
2027 /* set to null */
2028 DeviceEntry->PDODeviceName = NULL;
2029 }
2030
2031 /* set state no notstarted */
2032 DeviceEntry->DeviceState = NotStarted;
2033
2034 /* time to create PDO */
2035 KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
2036
2037 /* invalidate device relations */
2038 IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
2039
2040 /* done */
2041 Status = STATUS_SUCCESS;
2042 }
2043 else if (IoStack->MinorFunction == IRP_MN_QUERY_BUS_INFORMATION)
2044 {
2045 /* query bus information */
2046 Status = KspQueryBusInformation(ChildDeviceExtension, Irp);
2047 }
2048 else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES)
2049 {
2050 /* no op */
2051 Status = STATUS_SUCCESS;
2052 }
2053 else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
2054 {
2055 /* no op */
2056 Status = STATUS_SUCCESS;
2057 }
2058 else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
2059 {
2060 /* start bus */
2061 Status = KspStartBusDevice(DeviceObject, ChildDeviceExtension, Irp);
2062
2063 /* set time out */
2064 Time.QuadPart = Int32x32To64(1500, -10000);
2065
2066 /* sanity check */
2067 ASSERT(BusDeviceExtension);
2068
2069 /* set timer */
2070 KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
2071 }
2072 else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES)
2073 {
2074 /* query capabilities */
2075 Status = KspQueryBusDeviceCapabilities(ChildDeviceExtension, Irp);
2076 }
2077 else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
2078 {
2079 /* query pnp state */
2080 Status = KspQueryBusDevicePnpState(ChildDeviceExtension, Irp);
2081 }
2082 else if (IoStack->MinorFunction == IRP_MN_QUERY_INTERFACE)
2083 {
2084 /* query interface */
2085 Status = KspQueryBusDeviceInterface(ChildDeviceExtension, Irp);
2086 }
2087 else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS && IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
2088 {
2089 /* handle target device relations */
2090 ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation);
2091 ASSERT(Irp->IoStatus.Information == 0);
2092
2093 /* allocate device relation */
2094 DeviceRelation = AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
2095 if (DeviceRelation)
2096 {
2097 DeviceRelation->Count = 1;
2098 DeviceRelation->Objects[0] = DeviceObject;
2099
2100 /* reference self */
2101 ObReferenceObject(DeviceObject);
2102
2103 /* store result */
2104 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
2105
2106 /* done */
2107 Status = STATUS_SUCCESS;
2108 }
2109 else
2110 {
2111 /* no memory */
2112 Status = STATUS_INSUFFICIENT_RESOURCES;
2113 }
2114 }
2115 else
2116 {
2117 /* get default status */
2118 Status = Irp->IoStatus.Status;
2119 }
2120 }
2121
2122 DPRINT("KsServiceBusEnumPnpRequest %p Bus %u Function %x Status %x\n", DeviceObject, BusDeviceExtension->Common.IsBus, IoStack->MinorFunction, Status);
2123 Irp->IoStatus.Status = Status;
2124 return Status;
2125 }
2126
2127 /*
2128 @implemented
2129 */
2130 KSDDKAPI
2131 NTSTATUS
2132 NTAPI
2133 KsRemoveBusEnumInterface(
2134 IN PIRP Irp)
2135 {
2136 KPROCESSOR_MODE Mode;
2137 LUID luid;
2138 BUS_INSTALL_ENUM_CONTEXT Ctx;
2139 PDEV_EXTENSION DeviceExtension;
2140 PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
2141 PIO_STACK_LOCATION IoStack;
2142
2143 DPRINT1("KsRemoveBusEnumInterface\n");
2144
2145 /* get io stack location */
2146 IoStack = IoGetCurrentIrpStackLocation(Irp);
2147
2148 /* get device extension */
2149 DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
2150
2151 /* get bus device extension */
2152 BusDeviceExtension = DeviceExtension->Ext->BusDeviceExtension;
2153
2154 /* get previous mode */
2155 Mode = ExGetPreviousMode();
2156
2157 /* convert to luid */
2158 luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
2159
2160 /* perform access check */
2161 if (!SeSinglePrivilegeCheck(luid, Mode))
2162 {
2163 /* insufficient privileges */
2164 return STATUS_PRIVILEGE_NOT_HELD;
2165 }
2166
2167 /* initialize context */
2168 KeInitializeEvent(&Ctx.Event, NotificationEvent, FALSE);
2169 Ctx.Irp = Irp;
2170 Ctx.BusDeviceExtension = BusDeviceExtension;
2171 ExInitializeWorkItem(&Ctx.WorkItem, KspRemoveBusInterface, (PVOID)&Ctx);
2172
2173 /* now queue the work item */
2174 ExQueueWorkItem(&Ctx.WorkItem, DelayedWorkQueue);
2175
2176 /* wait for completion */
2177 KeWaitForSingleObject(&Ctx.Event, Executive, KernelMode, FALSE, NULL);
2178
2179 /* return result */
2180 return Ctx.Status;
2181 }