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