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