1 /*
2 * PROJECT: ReactOS ISA PnP Bus driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: PDO-specific code
5 * COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
6 * Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
7 * Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
8 */
9
10 #include "isapnp.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static
16 CODE_SEG("PAGE")
17 NTSTATUS
IsaPdoQueryDeviceRelations(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)18 IsaPdoQueryDeviceRelations(
19 _In_ PISAPNP_PDO_EXTENSION PdoExt,
20 _Inout_ PIRP Irp,
21 _In_ PIO_STACK_LOCATION IrpSp)
22 {
23 PDEVICE_RELATIONS DeviceRelations;
24
25 PAGED_CODE();
26
27 if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations &&
28 PdoExt->Common.Signature == IsaPnpReadDataPort)
29 {
30 return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE);
31 }
32
33 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
34 return Irp->IoStatus.Status;
35
36 DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(*DeviceRelations), TAG_ISAPNP);
37 if (!DeviceRelations)
38 return STATUS_NO_MEMORY;
39
40 DeviceRelations->Count = 1;
41 DeviceRelations->Objects[0] = PdoExt->Common.Self;
42 ObReferenceObject(PdoExt->Common.Self);
43
44 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
45 return STATUS_SUCCESS;
46 }
47
48 static
49 CODE_SEG("PAGE")
50 NTSTATUS
IsaPdoQueryCapabilities(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)51 IsaPdoQueryCapabilities(
52 _In_ PISAPNP_PDO_EXTENSION PdoExt,
53 _Inout_ PIRP Irp,
54 _In_ PIO_STACK_LOCATION IrpSp)
55 {
56 PDEVICE_CAPABILITIES DeviceCapabilities;
57 ULONG i;
58
59 UNREFERENCED_PARAMETER(Irp);
60
61 PAGED_CODE();
62
63 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
64 if (DeviceCapabilities->Version != 1)
65 return STATUS_REVISION_MISMATCH;
66
67 DeviceCapabilities->LockSupported =
68 DeviceCapabilities->EjectSupported =
69 DeviceCapabilities->Removable =
70 DeviceCapabilities->DockDevice = FALSE;
71
72 DeviceCapabilities->UniqueID = TRUE;
73
74 if (PdoExt->Common.Signature == IsaPnpReadDataPort)
75 {
76 DeviceCapabilities->RawDeviceOK = TRUE;
77 DeviceCapabilities->SilentInstall = TRUE;
78 }
79
80 for (i = 0; i < POWER_SYSTEM_MAXIMUM; i++)
81 DeviceCapabilities->DeviceState[i] = PowerDeviceD3;
82 DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
83
84 return STATUS_SUCCESS;
85 }
86
87 static
88 CODE_SEG("PAGE")
89 NTSTATUS
IsaPdoQueryPnpDeviceState(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp)90 IsaPdoQueryPnpDeviceState(
91 _In_ PISAPNP_PDO_EXTENSION PdoExt,
92 _Inout_ PIRP Irp)
93 {
94 PAGED_CODE();
95
96 if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE)
97 {
98 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE |
99 PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED |
100 PNP_DEVICE_FAILED;
101 return STATUS_SUCCESS;
102 }
103 else if (PdoExt->SpecialFiles > 0)
104 {
105 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
106 return STATUS_SUCCESS;
107 }
108
109 return Irp->IoStatus.Status;
110 }
111
112 static
113 CODE_SEG("PAGE")
114 NTSTATUS
IsaPdoQueryId(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)115 IsaPdoQueryId(
116 _In_ PISAPNP_PDO_EXTENSION PdoExt,
117 _Inout_ PIRP Irp,
118 _In_ PIO_STACK_LOCATION IrpSp)
119 {
120 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
121 NTSTATUS Status;
122 PWCHAR Buffer, End, IdStart;
123 size_t CharCount, Remaining;
124
125 PAGED_CODE();
126
127 switch (IrpSp->Parameters.QueryId.IdType)
128 {
129 case BusQueryDeviceID:
130 {
131 CharCount = sizeof("ISAPNP\\XXXFFFF");
132
133 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
134 {
135 CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
136 }
137
138 Buffer = ExAllocatePoolWithTag(PagedPool,
139 CharCount * sizeof(WCHAR),
140 TAG_ISAPNP);
141 if (!Buffer)
142 return STATUS_INSUFFICIENT_RESOURCES;
143
144 Status = RtlStringCchPrintfExW(Buffer,
145 CharCount,
146 &End,
147 &Remaining,
148 0,
149 L"ISAPNP\\%.3S%04X",
150 LogDev->VendorId,
151 LogDev->ProdId);
152 if (!NT_VERIFY(NT_SUCCESS(Status)))
153 goto Failure;
154
155 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
156 {
157 Status = RtlStringCchPrintfExW(End,
158 Remaining,
159 NULL,
160 NULL,
161 0,
162 L"_DEV%04X",
163 LogDev->LDN);
164 if (!NT_VERIFY(NT_SUCCESS(Status)))
165 goto Failure;
166 }
167
168 DPRINT("Device ID: '%S'\n", Buffer);
169 break;
170 }
171
172 case BusQueryHardwareIDs:
173 {
174 CharCount = sizeof("ISAPNP\\XXXFFFF") +
175 sizeof("*PNPxxxx") +
176 sizeof(ANSI_NULL); /* multi-string */
177
178 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
179 {
180 CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
181 }
182
183 Buffer = ExAllocatePoolWithTag(PagedPool,
184 CharCount * sizeof(WCHAR),
185 TAG_ISAPNP);
186 if (!Buffer)
187 return STATUS_INSUFFICIENT_RESOURCES;
188
189 DPRINT("Hardware IDs:\n");
190
191 /* 1 */
192 Status = RtlStringCchPrintfExW(Buffer,
193 CharCount,
194 &End,
195 &Remaining,
196 0,
197 L"ISAPNP\\%.3S%04X",
198 LogDev->VendorId,
199 LogDev->ProdId);
200 if (!NT_VERIFY(NT_SUCCESS(Status)))
201 goto Failure;
202
203 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
204 {
205 Status = RtlStringCchPrintfExW(End,
206 Remaining,
207 &End,
208 &Remaining,
209 0,
210 L"_DEV%04X",
211 LogDev->LDN);
212 if (!NT_VERIFY(NT_SUCCESS(Status)))
213 goto Failure;
214 }
215
216 DPRINT(" '%S'\n", Buffer);
217
218 ++End;
219 --Remaining;
220
221 /* 2 */
222 IdStart = End;
223 Status = RtlStringCchPrintfExW(End,
224 Remaining,
225 &End,
226 &Remaining,
227 0,
228 L"*%.3S%04X",
229 LogDev->LogVendorId,
230 LogDev->LogProdId);
231 if (!NT_VERIFY(NT_SUCCESS(Status)))
232 goto Failure;
233
234 DPRINT(" '%S'\n", IdStart);
235
236 *++End = UNICODE_NULL;
237 --Remaining;
238
239 break;
240 }
241
242 case BusQueryCompatibleIDs:
243 {
244 PLIST_ENTRY Entry;
245
246 for (Entry = LogDev->CompatibleIdList.Flink, CharCount = 0;
247 Entry != &LogDev->CompatibleIdList;
248 Entry = Entry->Flink)
249 {
250 CharCount += sizeof("*PNPxxxx");
251 }
252 CharCount += sizeof(ANSI_NULL); /* multi-string */
253
254 if (CharCount == sizeof(ANSI_NULL))
255 return Irp->IoStatus.Status;
256
257 Buffer = ExAllocatePoolWithTag(PagedPool,
258 CharCount * sizeof(WCHAR),
259 TAG_ISAPNP);
260 if (!Buffer)
261 return STATUS_INSUFFICIENT_RESOURCES;
262
263 DPRINT("Compatible IDs:\n");
264
265 for (Entry = LogDev->CompatibleIdList.Flink, End = Buffer, Remaining = CharCount;
266 Entry != &LogDev->CompatibleIdList;
267 Entry = Entry->Flink)
268 {
269 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
270 CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
271
272 IdStart = End;
273 Status = RtlStringCchPrintfExW(End,
274 Remaining,
275 &End,
276 &Remaining,
277 0,
278 L"*%.3S%04X",
279 CompatibleId->VendorId,
280 CompatibleId->ProdId);
281 if (!NT_VERIFY(NT_SUCCESS(Status)))
282 goto Failure;
283
284 DPRINT(" '%S'\n", IdStart);
285
286 ++End;
287 --Remaining;
288 }
289
290 *End = UNICODE_NULL;
291
292 break;
293 }
294
295 case BusQueryInstanceID:
296 {
297 CharCount = sizeof(LogDev->SerialNumber) * 2 + sizeof(ANSI_NULL);
298
299 Buffer = ExAllocatePoolWithTag(PagedPool,
300 CharCount * sizeof(WCHAR),
301 TAG_ISAPNP);
302 if (!Buffer)
303 return STATUS_INSUFFICIENT_RESOURCES;
304
305 Status = RtlStringCchPrintfExW(Buffer,
306 CharCount,
307 NULL,
308 NULL,
309 0,
310 L"%X",
311 LogDev->SerialNumber);
312 if (!NT_VERIFY(NT_SUCCESS(Status)))
313 goto Failure;
314
315 DPRINT("Instance ID: '%S'\n", Buffer);
316 break;
317 }
318
319 default:
320 return Irp->IoStatus.Status;
321 }
322
323 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
324 return STATUS_SUCCESS;
325
326 Failure:
327 ExFreePoolWithTag(Buffer, TAG_ISAPNP);
328
329 return Status;
330 }
331
332 static
333 CODE_SEG("PAGE")
334 NTSTATUS
IsaReadPortQueryId(_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)335 IsaReadPortQueryId(
336 _Inout_ PIRP Irp,
337 _In_ PIO_STACK_LOCATION IrpSp)
338 {
339 PWCHAR Buffer;
340 static const WCHAR ReadPortId[] = L"ISAPNP\\ReadDataPort";
341
342 PAGED_CODE();
343
344 switch (IrpSp->Parameters.QueryId.IdType)
345 {
346 case BusQueryDeviceID:
347 {
348 Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(ReadPortId), TAG_ISAPNP);
349 if (!Buffer)
350 return STATUS_INSUFFICIENT_RESOURCES;
351
352 RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId));
353
354 DPRINT("Device ID: '%S'\n", Buffer);
355 break;
356 }
357
358 case BusQueryHardwareIDs:
359 {
360 Buffer = ExAllocatePoolWithTag(PagedPool,
361 sizeof(ReadPortId) + sizeof(UNICODE_NULL),
362 TAG_ISAPNP);
363 if (!Buffer)
364 return STATUS_INSUFFICIENT_RESOURCES;
365
366 RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId));
367
368 Buffer[sizeof(ReadPortId) / sizeof(WCHAR)] = UNICODE_NULL; /* multi-string */
369
370 DPRINT("Hardware ID: '%S'\n", Buffer);
371 break;
372 }
373
374 case BusQueryCompatibleIDs:
375 {
376 /* Empty multi-string */
377 Buffer = ExAllocatePoolZero(PagedPool, sizeof(UNICODE_NULL) * 2, TAG_ISAPNP);
378 if (!Buffer)
379 return STATUS_INSUFFICIENT_RESOURCES;
380
381 DPRINT("Compatible ID: '%S'\n", Buffer);
382 break;
383 }
384
385 case BusQueryInstanceID:
386 {
387 /* Even if there are multiple ISA buses, the driver has only one Read Port */
388 static const WCHAR InstanceId[] = L"0";
389
390 Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(InstanceId), TAG_ISAPNP);
391 if (!Buffer)
392 return STATUS_INSUFFICIENT_RESOURCES;
393
394 RtlCopyMemory(Buffer, InstanceId, sizeof(InstanceId));
395
396 DPRINT("Instance ID: '%S'\n", Buffer);
397 break;
398 }
399
400 default:
401 return Irp->IoStatus.Status;
402 }
403
404 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
405 return STATUS_SUCCESS;
406 }
407
408 static
409 CODE_SEG("PAGE")
410 NTSTATUS
IsaPdoQueryDeviceText(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)411 IsaPdoQueryDeviceText(
412 _In_ PISAPNP_PDO_EXTENSION PdoExt,
413 _Inout_ PIRP Irp,
414 _In_ PIO_STACK_LOCATION IrpSp)
415 {
416 NTSTATUS Status;
417 PWCHAR Buffer;
418 size_t CharCount;
419
420 PAGED_CODE();
421
422 switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
423 {
424 case DeviceTextDescription:
425 {
426 if (!PdoExt->IsaPnpDevice->FriendlyName)
427 return Irp->IoStatus.Status;
428
429 CharCount = strlen(PdoExt->IsaPnpDevice->FriendlyName) +
430 sizeof(ANSI_NULL);
431
432 if (CharCount == sizeof(ANSI_NULL))
433 return Irp->IoStatus.Status;
434
435 Buffer = ExAllocatePoolWithTag(PagedPool,
436 CharCount * sizeof(WCHAR),
437 TAG_ISAPNP);
438 if (!Buffer)
439 return STATUS_INSUFFICIENT_RESOURCES;
440
441 Status = RtlStringCchPrintfExW(Buffer,
442 CharCount,
443 NULL,
444 NULL,
445 0,
446 L"%hs",
447 PdoExt->IsaPnpDevice->FriendlyName);
448 if (!NT_VERIFY(NT_SUCCESS(Status)))
449 {
450 ExFreePoolWithTag(Buffer, TAG_ISAPNP);
451 return Status;
452 }
453
454 DPRINT("TextDescription: '%S'\n", Buffer);
455 break;
456 }
457
458 default:
459 return Irp->IoStatus.Status;
460 }
461
462 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
463 return STATUS_SUCCESS;
464 }
465
466 static
467 CODE_SEG("PAGE")
468 NTSTATUS
IsaPdoQueryResources(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)469 IsaPdoQueryResources(
470 _In_ PISAPNP_PDO_EXTENSION PdoExt,
471 _Inout_ PIRP Irp,
472 _In_ PIO_STACK_LOCATION IrpSp)
473 {
474 ULONG ListSize;
475 PCM_RESOURCE_LIST ResourceList;
476
477 UNREFERENCED_PARAMETER(IrpSp);
478
479 PAGED_CODE();
480
481 if (PdoExt->Common.Signature == IsaPnpReadDataPort)
482 {
483 ResourceList = IsaPnpCreateReadPortDOResources();
484 if (!ResourceList)
485 return STATUS_NO_MEMORY;
486
487 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
488 return STATUS_SUCCESS;
489 }
490
491 if (!PdoExt->ResourceList)
492 return Irp->IoStatus.Status;
493
494 ListSize = PdoExt->ResourceListSize;
495 ResourceList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP);
496 if (!ResourceList)
497 return STATUS_NO_MEMORY;
498
499 RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize);
500 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
501 return STATUS_SUCCESS;
502 }
503
504 static
505 CODE_SEG("PAGE")
506 NTSTATUS
IsaPdoQueryResourceRequirements(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)507 IsaPdoQueryResourceRequirements(
508 _In_ PISAPNP_PDO_EXTENSION PdoExt,
509 _Inout_ PIRP Irp,
510 _In_ PIO_STACK_LOCATION IrpSp)
511 {
512 ULONG ListSize;
513 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
514
515 UNREFERENCED_PARAMETER(IrpSp);
516
517 PAGED_CODE();
518
519 if (PdoExt->Common.Signature == IsaPnpReadDataPort)
520 {
521 RequirementsList = IsaPnpCreateReadPortDORequirements(PdoExt->SelectedPort);
522 if (!RequirementsList)
523 return STATUS_NO_MEMORY;
524
525 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
526 return STATUS_SUCCESS;
527 }
528
529 if (!PdoExt->RequirementsList)
530 return Irp->IoStatus.Status;
531
532 ListSize = PdoExt->RequirementsList->ListSize;
533 RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP);
534 if (!RequirementsList)
535 return STATUS_NO_MEMORY;
536
537 RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize);
538 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
539 return STATUS_SUCCESS;
540 }
541
542 #define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && (_d)->u.Port.Length > 1)
543
544 static
545 CODE_SEG("PAGE")
546 NTSTATUS
IsaPdoStartReadPort(_In_ PISAPNP_PDO_EXTENSION PdoExt,_In_ PCM_RESOURCE_LIST ResourceList)547 IsaPdoStartReadPort(
548 _In_ PISAPNP_PDO_EXTENSION PdoExt,
549 _In_ PCM_RESOURCE_LIST ResourceList)
550 {
551 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
552 NTSTATUS Status;
553 ULONG i;
554
555 PAGED_CODE();
556
557 if (!ResourceList)
558 {
559 DPRINT1("No resource list\n");
560 return STATUS_INSUFFICIENT_RESOURCES;
561 }
562
563 if (ResourceList->List[0].PartialResourceList.Version != 1 ||
564 ResourceList->List[0].PartialResourceList.Revision != 1)
565 {
566 DPRINT1("Bad resource list version (%u.%u)\n",
567 ResourceList->List[0].PartialResourceList.Version,
568 ResourceList->List[0].PartialResourceList.Revision);
569 return STATUS_REVISION_MISMATCH;
570 }
571
572 #if 0
573 /* Try various Read Ports from the list */
574 if (ResourceList->List[0].PartialResourceList.Count > 3)
575 {
576 ULONG SelectedPort = 0;
577
578 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
579 {
580 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
581 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
582
583 if (IS_READ_PORT(PartialDescriptor))
584 {
585 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
586 ULONG Cards;
587
588 /*
589 * Remember the first Read Port in the resource list.
590 * It will be selected by default even if no card has been detected.
591 */
592 if (!SelectedPort)
593 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
594
595 Cards = IsaHwTryReadDataPort(ReadDataPort);
596 IsaHwWaitForKey();
597
598 /* We detected some ISAPNP cards */
599 if (Cards > 0)
600 {
601 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
602 break;
603 }
604 }
605 }
606
607 ASSERT(SelectedPort != 0);
608
609 /* Discard the Read Ports at conflicting locations */
610 PdoExt->SelectedPort = SelectedPort;
611 PdoExt->Flags |= ISAPNP_READ_PORT_NEED_REBALANCE;
612 IoInvalidateDeviceState(PdoExt->Common.Self);
613
614 return STATUS_SUCCESS;
615 }
616 /* Set the Read Port */
617 else if (ResourceList->List[0].PartialResourceList.Count == 3)
618 #else
619 if (ResourceList->List[0].PartialResourceList.Count > 3) /* Temporary HACK */
620 #endif
621 {
622 PdoExt->Flags &= ~ISAPNP_READ_PORT_NEED_REBALANCE;
623
624 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
625 {
626 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
627 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
628
629 if (IS_READ_PORT(PartialDescriptor))
630 {
631 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
632
633 /* Run the isolation protocol */
634 FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort);
635
636 if (FdoExt->Cards > 0)
637 {
638 FdoExt->ReadDataPort = ReadDataPort;
639
640 IsaPnpAcquireDeviceDataLock(FdoExt);
641
642 /* Card identification */
643 Status = IsaHwFillDeviceList(FdoExt);
644 IsaHwWaitForKey();
645
646 IsaPnpReleaseDeviceDataLock(FdoExt);
647
648 PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
649 ISAPNP_SCANNED_BY_READ_PORT;
650
651 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
652 IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations);
653
654 return Status;
655 }
656 else
657 {
658 IsaHwWaitForKey();
659 #if 0 /* See the 'if 0' above */
660 break;
661 #endif
662 }
663 }
664 }
665 }
666 else
667 {
668 return STATUS_DEVICE_CONFIGURATION_ERROR;
669 }
670
671 /* Mark Read Port as started, even if no card has been detected */
672 return STATUS_SUCCESS;
673 }
674
675 static
676 CODE_SEG("PAGE")
677 NTSTATUS
IsaPdoFilterResourceRequirements(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)678 IsaPdoFilterResourceRequirements(
679 _In_ PISAPNP_PDO_EXTENSION PdoExt,
680 _Inout_ PIRP Irp,
681 _In_ PIO_STACK_LOCATION IrpSp)
682 {
683 PAGED_CODE();
684
685 /* TODO: Handle */
686 UNREFERENCED_PARAMETER(PdoExt);
687 UNREFERENCED_PARAMETER(IrpSp);
688 return Irp->IoStatus.Status;
689 }
690
691 static
692 CODE_SEG("PAGE")
693 NTSTATUS
IsaPdoQueryBusInformation(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp)694 IsaPdoQueryBusInformation(
695 _In_ PISAPNP_PDO_EXTENSION PdoExt,
696 _Inout_ PIRP Irp)
697 {
698 PPNP_BUS_INFORMATION BusInformation;
699
700 PAGED_CODE();
701
702 BusInformation = ExAllocatePoolWithTag(PagedPool,
703 sizeof(PNP_BUS_INFORMATION),
704 TAG_ISAPNP);
705 if (!BusInformation)
706 return STATUS_INSUFFICIENT_RESOURCES;
707
708 BusInformation->BusTypeGuid = GUID_BUS_TYPE_ISAPNP;
709 BusInformation->LegacyBusType = Isa;
710 BusInformation->BusNumber = PdoExt->FdoExt->BusNumber;
711
712 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
713 return STATUS_SUCCESS;
714 }
715
716 static
717 CODE_SEG("PAGE")
718 NTSTATUS
IsaPdoQueryDeviceUsageNotification(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)719 IsaPdoQueryDeviceUsageNotification(
720 _In_ PISAPNP_PDO_EXTENSION PdoExt,
721 _Inout_ PIRP Irp,
722 _In_ PIO_STACK_LOCATION IrpSp)
723 {
724 BOOLEAN InPath = IrpSp->Parameters.UsageNotification.InPath;
725
726 PAGED_CODE();
727
728 switch (IrpSp->Parameters.UsageNotification.Type)
729 {
730 case DeviceUsageTypePaging:
731 case DeviceUsageTypeHibernation:
732 case DeviceUsageTypeDumpFile:
733 IoAdjustPagingPathCount(&PdoExt->SpecialFiles, InPath);
734 IoInvalidateDeviceState(PdoExt->Common.Self);
735 break;
736
737 default:
738 return Irp->IoStatus.Status;
739 }
740
741 /* Do not send it to FDO for compatibility */
742 return STATUS_SUCCESS;
743 }
744
745 static
746 CODE_SEG("PAGE")
747 NTSTATUS
IsaPdoRemoveDevice(_In_ PISAPNP_PDO_EXTENSION PdoExt,_In_ BOOLEAN FinalRemove)748 IsaPdoRemoveDevice(
749 _In_ PISAPNP_PDO_EXTENSION PdoExt,
750 _In_ BOOLEAN FinalRemove)
751 {
752 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
753
754 PAGED_CODE();
755
756 /* Deactivate the device if previously activated */
757 if (PdoExt->Common.State == dsStarted)
758 {
759 IsaHwWakeDevice(PdoExt->IsaPnpDevice);
760 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice);
761
762 IsaHwWaitForKey();
763
764 PdoExt->Common.State = dsStopped;
765 }
766
767 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED))
768 {
769 IsaPnpAcquireDeviceDataLock(FdoExt);
770
771 RemoveEntryList(&PdoExt->IsaPnpDevice->DeviceLink);
772 --FdoExt->DeviceCount;
773
774 IsaPnpReleaseDeviceDataLock(FdoExt);
775
776 IsaPnpRemoveLogicalDeviceDO(PdoExt->Common.Self);
777 }
778
779 return STATUS_SUCCESS;
780 }
781
782 static
783 CODE_SEG("PAGE")
784 NTSTATUS
IsaReadPortRemoveDevice(_In_ PISAPNP_PDO_EXTENSION PdoExt,_In_ BOOLEAN FinalRemove)785 IsaReadPortRemoveDevice(
786 _In_ PISAPNP_PDO_EXTENSION PdoExt,
787 _In_ BOOLEAN FinalRemove)
788 {
789 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
790 PLIST_ENTRY Entry;
791
792 PAGED_CODE();
793
794 IsaPnpAcquireDeviceDataLock(FdoExt);
795
796 /* Logical devices will receive a remove request afterwards */
797 for (Entry = FdoExt->DeviceListHead.Flink;
798 Entry != &FdoExt->DeviceListHead;
799 Entry = Entry->Flink)
800 {
801 PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(Entry,
802 ISAPNP_LOGICAL_DEVICE,
803 DeviceLink);
804
805 LogDevice->Flags &= ~ISAPNP_PRESENT;
806 }
807
808 IsaPnpReleaseDeviceDataLock(FdoExt);
809
810 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN;
811 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
812
813 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED))
814 {
815 IsaPnpRemoveReadPortDO(PdoExt->Common.Self);
816 }
817
818 return STATUS_SUCCESS;
819 }
820
821 CODE_SEG("PAGE")
822 VOID
IsaPnpRemoveLogicalDeviceDO(_In_ PDEVICE_OBJECT Pdo)823 IsaPnpRemoveLogicalDeviceDO(
824 _In_ PDEVICE_OBJECT Pdo)
825 {
826 PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension;
827 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
828 PLIST_ENTRY Entry;
829
830 PAGED_CODE();
831 ASSERT(LogDev);
832
833 DPRINT("Removing CSN %u, LDN %u\n", LogDev->CSN, LogDev->LDN);
834
835 if (PdoExt->RequirementsList)
836 ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
837
838 if (PdoExt->ResourceList)
839 ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
840
841 if (LogDev->FriendlyName)
842 ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP);
843
844 if (LogDev->Resources)
845 ExFreePoolWithTag(LogDev->Resources, TAG_ISAPNP);
846
847 Entry = LogDev->CompatibleIdList.Flink;
848 while (Entry != &LogDev->CompatibleIdList)
849 {
850 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
851 CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
852
853 RemoveEntryList(&CompatibleId->IdLink);
854
855 Entry = Entry->Flink;
856
857 ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
858 }
859
860 ExFreePoolWithTag(LogDev, TAG_ISAPNP);
861
862 IoDeleteDevice(PdoExt->Common.Self);
863 }
864
865 CODE_SEG("PAGE")
866 NTSTATUS
IsaPdoPnp(_In_ PISAPNP_PDO_EXTENSION PdoExt,_Inout_ PIRP Irp,_In_ PIO_STACK_LOCATION IrpSp)867 IsaPdoPnp(
868 _In_ PISAPNP_PDO_EXTENSION PdoExt,
869 _Inout_ PIRP Irp,
870 _In_ PIO_STACK_LOCATION IrpSp)
871 {
872 NTSTATUS Status = Irp->IoStatus.Status;
873
874 PAGED_CODE();
875
876 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
877 {
878 DPRINT("%s(%p, %p) CSN %u, LDN %u, Minor - %X\n",
879 __FUNCTION__,
880 PdoExt,
881 Irp,
882 PdoExt->IsaPnpDevice->CSN,
883 PdoExt->IsaPnpDevice->LDN,
884 IrpSp->MinorFunction);
885 }
886 else
887 {
888 DPRINT("%s(%p, %p) ReadPort, Minor - %X\n",
889 __FUNCTION__,
890 PdoExt,
891 Irp,
892 IrpSp->MinorFunction);
893 }
894
895 switch (IrpSp->MinorFunction)
896 {
897 case IRP_MN_START_DEVICE:
898 {
899 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
900 {
901 IsaHwWakeDevice(PdoExt->IsaPnpDevice);
902
903 Status = IsaHwConfigureDevice(PdoExt->FdoExt,
904 PdoExt->IsaPnpDevice,
905 IrpSp->Parameters.StartDevice.AllocatedResources);
906 if (NT_SUCCESS(Status))
907 {
908 IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice);
909 }
910 else
911 {
912 DPRINT1("Failed to configure CSN %u, LDN %u with status 0x%08lx\n",
913 PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, Status);
914 }
915
916 IsaHwWaitForKey();
917 }
918 else
919 {
920 Status = IsaPdoStartReadPort(PdoExt,
921 IrpSp->Parameters.StartDevice.AllocatedResources);
922 }
923
924 if (NT_SUCCESS(Status))
925 PdoExt->Common.State = dsStarted;
926 break;
927 }
928
929 case IRP_MN_STOP_DEVICE:
930 {
931 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
932 {
933 IsaHwWakeDevice(PdoExt->IsaPnpDevice);
934 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice);
935
936 IsaHwWaitForKey();
937 }
938 else
939 {
940 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN;
941 }
942
943 Status = STATUS_SUCCESS;
944
945 if (NT_SUCCESS(Status))
946 PdoExt->Common.State = dsStopped;
947 break;
948 }
949
950 case IRP_MN_QUERY_STOP_DEVICE:
951 {
952 if (PdoExt->SpecialFiles > 0)
953 Status = STATUS_DEVICE_BUSY;
954 else if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE)
955 Status = STATUS_RESOURCE_REQUIREMENTS_CHANGED;
956 else
957 Status = STATUS_SUCCESS;
958
959 break;
960 }
961
962 case IRP_MN_QUERY_REMOVE_DEVICE:
963 {
964 if (PdoExt->SpecialFiles > 0)
965 Status = STATUS_DEVICE_BUSY;
966 else
967 Status = STATUS_SUCCESS;
968 break;
969 }
970
971 case IRP_MN_QUERY_DEVICE_RELATIONS:
972 Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp);
973 break;
974
975 case IRP_MN_QUERY_CAPABILITIES:
976 Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp);
977 break;
978
979 case IRP_MN_SURPRISE_REMOVAL:
980 case IRP_MN_REMOVE_DEVICE:
981 {
982 BOOLEAN FinalRemove = (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE);
983
984 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
985 Status = IsaPdoRemoveDevice(PdoExt, FinalRemove);
986 else
987 Status = IsaReadPortRemoveDevice(PdoExt, FinalRemove);
988 break;
989 }
990
991 case IRP_MN_QUERY_PNP_DEVICE_STATE:
992 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp);
993 break;
994
995 case IRP_MN_QUERY_RESOURCES:
996 Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp);
997 break;
998
999 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1000 Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp);
1001 break;
1002
1003 case IRP_MN_QUERY_ID:
1004 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
1005 Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
1006 else
1007 Status = IsaReadPortQueryId(Irp, IrpSp);
1008 break;
1009
1010 case IRP_MN_QUERY_DEVICE_TEXT:
1011 if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
1012 Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp);
1013 break;
1014
1015 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1016 Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp);
1017 break;
1018
1019 case IRP_MN_QUERY_BUS_INFORMATION:
1020 Status = IsaPdoQueryBusInformation(PdoExt, Irp);
1021 break;
1022
1023 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
1024 Status = IsaPdoQueryDeviceUsageNotification(PdoExt, Irp, IrpSp);
1025 break;
1026
1027 case IRP_MN_CANCEL_REMOVE_DEVICE:
1028 case IRP_MN_CANCEL_STOP_DEVICE:
1029 Status = STATUS_SUCCESS;
1030 break;
1031
1032 default:
1033 DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction);
1034 break;
1035 }
1036
1037 Irp->IoStatus.Status = Status;
1038 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1039
1040 return Status;
1041 }
1042