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