xref: /reactos/drivers/bus/isapnp/isapnp.c (revision 66c19575)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS ISA PnP Bus driver
38f44930fSDmitry Borisov  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4c2c66affSColin Finck  * PURPOSE:         Driver entry
58f44930fSDmitry Borisov  * COPYRIGHT:       Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
68f44930fSDmitry Borisov  *                  Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
98f44930fSDmitry Borisov #include "isapnp.h"
10c2c66affSColin Finck 
11c2c66affSColin Finck #define NDEBUG
12c2c66affSColin Finck #include <debug.h>
13c2c66affSColin Finck 
1489aff07aSHervé Poussineau NTSTATUS
1589aff07aSHervé Poussineau NTAPI
16e0607fceSHervé Poussineau IsaPnpDuplicateUnicodeString(
17e0607fceSHervé Poussineau     IN ULONG Flags,
18e0607fceSHervé Poussineau     IN PCUNICODE_STRING SourceString,
19e0607fceSHervé Poussineau     OUT PUNICODE_STRING DestinationString)
20e0607fceSHervé Poussineau {
21e0607fceSHervé Poussineau     if (SourceString == NULL ||
22e0607fceSHervé Poussineau         DestinationString == NULL ||
23e0607fceSHervé Poussineau         SourceString->Length > SourceString->MaximumLength ||
24e0607fceSHervé Poussineau         (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
25e0607fceSHervé Poussineau         Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
26e0607fceSHervé Poussineau         Flags >= 4)
27e0607fceSHervé Poussineau     {
28e0607fceSHervé Poussineau         return STATUS_INVALID_PARAMETER;
29e0607fceSHervé Poussineau     }
30e0607fceSHervé Poussineau 
31e0607fceSHervé Poussineau     if ((SourceString->Length == 0) &&
32e0607fceSHervé Poussineau         (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
33e0607fceSHervé Poussineau                    RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
34e0607fceSHervé Poussineau     {
35e0607fceSHervé Poussineau         DestinationString->Length = 0;
36e0607fceSHervé Poussineau         DestinationString->MaximumLength = 0;
37e0607fceSHervé Poussineau         DestinationString->Buffer = NULL;
38e0607fceSHervé Poussineau     }
39e0607fceSHervé Poussineau     else
40e0607fceSHervé Poussineau     {
41e0607fceSHervé Poussineau         USHORT DestMaxLength = SourceString->Length;
42e0607fceSHervé Poussineau 
43e0607fceSHervé Poussineau         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
44e0607fceSHervé Poussineau             DestMaxLength += sizeof(UNICODE_NULL);
45e0607fceSHervé Poussineau 
46e0607fceSHervé Poussineau         DestinationString->Buffer = ExAllocatePool(PagedPool, DestMaxLength);
47e0607fceSHervé Poussineau         if (DestinationString->Buffer == NULL)
48e0607fceSHervé Poussineau             return STATUS_NO_MEMORY;
49e0607fceSHervé Poussineau 
50e0607fceSHervé Poussineau         RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
51e0607fceSHervé Poussineau         DestinationString->Length = SourceString->Length;
52e0607fceSHervé Poussineau         DestinationString->MaximumLength = DestMaxLength;
53e0607fceSHervé Poussineau 
54e0607fceSHervé Poussineau         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
55e0607fceSHervé Poussineau             DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
56e0607fceSHervé Poussineau     }
57e0607fceSHervé Poussineau 
58e0607fceSHervé Poussineau     return STATUS_SUCCESS;
59e0607fceSHervé Poussineau }
60e0607fceSHervé Poussineau 
61e0607fceSHervé Poussineau static
62e0607fceSHervé Poussineau NTSTATUS
63e0607fceSHervé Poussineau NTAPI
64e0607fceSHervé Poussineau IsaFdoCreateDeviceIDs(
65e0607fceSHervé Poussineau     IN PISAPNP_PDO_EXTENSION PdoExt)
66e0607fceSHervé Poussineau {
67e0607fceSHervé Poussineau     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
68e0607fceSHervé Poussineau     UNICODE_STRING TempString;
69e0607fceSHervé Poussineau     WCHAR TempBuffer[256];
70e0607fceSHervé Poussineau     PWCHAR End;
71e0607fceSHervé Poussineau     NTSTATUS Status;
72e0607fceSHervé Poussineau     USHORT i;
73e0607fceSHervé Poussineau 
74e0607fceSHervé Poussineau     TempString.Buffer = TempBuffer;
75e0607fceSHervé Poussineau     TempString.MaximumLength = sizeof(TempBuffer);
76e0607fceSHervé Poussineau     TempString.Length = 0;
77e0607fceSHervé Poussineau 
78e0607fceSHervé Poussineau     /* Device ID */
79e0607fceSHervé Poussineau     Status = RtlStringCbPrintfExW(TempString.Buffer,
80e0607fceSHervé Poussineau                                   TempString.MaximumLength / sizeof(WCHAR),
81e0607fceSHervé Poussineau                                   &End,
82e0607fceSHervé Poussineau                                   NULL, 0,
83eb66324dSHervé Poussineau                                   L"ISAPNP\\%.3S%04x",
84e0607fceSHervé Poussineau                                   LogDev->VendorId,
85e0607fceSHervé Poussineau                                   LogDev->ProdId);
86e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
87e0607fceSHervé Poussineau         return Status;
887b1e28e7SHervé Poussineau     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
89e0607fceSHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(
90e0607fceSHervé Poussineau         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
91e0607fceSHervé Poussineau         &TempString,
92e0607fceSHervé Poussineau         &PdoExt->DeviceID);
93e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
94e0607fceSHervé Poussineau         return Status;
95e0607fceSHervé Poussineau 
96e0607fceSHervé Poussineau     /* HardwareIDs */
97e0607fceSHervé Poussineau     Status = RtlStringCbPrintfExW(TempString.Buffer,
98e0607fceSHervé Poussineau                                   TempString.MaximumLength / sizeof(WCHAR),
99e0607fceSHervé Poussineau                                   &End,
100e0607fceSHervé Poussineau                                   NULL, 0,
101eb66324dSHervé Poussineau                                   L"ISAPNP\\%.3S%04x@"
102eb66324dSHervé Poussineau                                   L"*%.3S%04x@",
103e0607fceSHervé Poussineau                                   LogDev->VendorId,
104e0607fceSHervé Poussineau                                   LogDev->ProdId,
105e0607fceSHervé Poussineau                                   LogDev->VendorId,
106e0607fceSHervé Poussineau                                   LogDev->ProdId);
107e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
108e0607fceSHervé Poussineau         return Status;
1097b1e28e7SHervé Poussineau     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
110e0607fceSHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(
111e0607fceSHervé Poussineau         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
112e0607fceSHervé Poussineau         &TempString,
113e0607fceSHervé Poussineau         &PdoExt->HardwareIDs);
114e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
115e0607fceSHervé Poussineau         return Status;
116e0607fceSHervé Poussineau     for (i = 0; i < PdoExt->HardwareIDs.Length / sizeof(WCHAR); i++)
117e0607fceSHervé Poussineau         if (PdoExt->HardwareIDs.Buffer[i] == '@')
118e0607fceSHervé Poussineau             PdoExt->HardwareIDs.Buffer[i] = UNICODE_NULL;
119e0607fceSHervé Poussineau 
120e0607fceSHervé Poussineau     /* InstanceID */
121e0607fceSHervé Poussineau     Status = RtlStringCbPrintfExW(TempString.Buffer,
122e0607fceSHervé Poussineau                                   TempString.MaximumLength / sizeof(WCHAR),
123e0607fceSHervé Poussineau                                   &End,
124e0607fceSHervé Poussineau                                   NULL, 0,
125e0607fceSHervé Poussineau                                   L"%X",
126e0607fceSHervé Poussineau                                   LogDev->SerialNumber);
127e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
128e0607fceSHervé Poussineau         return Status;
1297b1e28e7SHervé Poussineau     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
130e0607fceSHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(
131e0607fceSHervé Poussineau         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
132e0607fceSHervé Poussineau         &TempString,
133e0607fceSHervé Poussineau         &PdoExt->InstanceID);
134e0607fceSHervé Poussineau     if (!NT_SUCCESS(Status))
135e0607fceSHervé Poussineau         return Status;
136e0607fceSHervé Poussineau 
137e0607fceSHervé Poussineau     return STATUS_SUCCESS;
138e0607fceSHervé Poussineau }
139e0607fceSHervé Poussineau 
14067141abeSHervé Poussineau static
14167141abeSHervé Poussineau NTSTATUS
14267141abeSHervé Poussineau NTAPI
1438f44930fSDmitry Borisov IsaPnpCreateLogicalDeviceRequirements(
1448f44930fSDmitry Borisov     _In_ PISAPNP_PDO_EXTENSION PdoExt)
14567141abeSHervé Poussineau {
14667141abeSHervé Poussineau     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
1478f44930fSDmitry Borisov     RTL_BITMAP IrqBitmap[RTL_NUMBER_OF(LogDev->Irq)];
1488f44930fSDmitry Borisov     RTL_BITMAP DmaBitmap[RTL_NUMBER_OF(LogDev->Dma)];
1498f44930fSDmitry Borisov     ULONG IrqData[RTL_NUMBER_OF(LogDev->Irq)];
1508f44930fSDmitry Borisov     ULONG DmaData[RTL_NUMBER_OF(LogDev->Dma)];
15167141abeSHervé Poussineau     ULONG ResourceCount = 0;
15267141abeSHervé Poussineau     ULONG ListSize, i, j;
1537cda1ed2SHervé Poussineau     BOOLEAN FirstIrq = TRUE, FirstDma = TRUE;
15467141abeSHervé Poussineau     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
15567141abeSHervé Poussineau     PIO_RESOURCE_DESCRIPTOR Descriptor;
15667141abeSHervé Poussineau 
15767141abeSHervé Poussineau     /* Count number of requirements */
1588f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
15967141abeSHervé Poussineau     {
16067141abeSHervé Poussineau         if (!LogDev->Io[i].Description.Length)
16167141abeSHervé Poussineau             break;
1628f44930fSDmitry Borisov 
16367141abeSHervé Poussineau         ResourceCount++;
16467141abeSHervé Poussineau     }
1658f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
16667141abeSHervé Poussineau     {
16767141abeSHervé Poussineau         if (!LogDev->Irq[i].Description.Mask)
16867141abeSHervé Poussineau             break;
1698f44930fSDmitry Borisov 
17067141abeSHervé Poussineau         IrqData[i] = LogDev->Irq[i].Description.Mask;
17167141abeSHervé Poussineau         RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16);
17267141abeSHervé Poussineau         ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
1738f44930fSDmitry Borisov 
17467141abeSHervé Poussineau         if (LogDev->Irq[i].Description.Information & 0x4)
17567141abeSHervé Poussineau         {
17667141abeSHervé Poussineau             /* Add room for level sensitive */
17767141abeSHervé Poussineau             ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
17867141abeSHervé Poussineau         }
17967141abeSHervé Poussineau     }
18067141abeSHervé Poussineau     if (ResourceCount == 0)
18167141abeSHervé Poussineau         return STATUS_SUCCESS;
1828f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
1837cda1ed2SHervé Poussineau     {
1847cda1ed2SHervé Poussineau         if (!LogDev->Dma[i].Description.Mask)
1857cda1ed2SHervé Poussineau             break;
1868f44930fSDmitry Borisov 
1877cda1ed2SHervé Poussineau         DmaData[i] = LogDev->Dma[i].Description.Mask;
1887cda1ed2SHervé Poussineau         RtlInitializeBitMap(&DmaBitmap[i], &DmaData[i], 8);
1897cda1ed2SHervé Poussineau         ResourceCount += RtlNumberOfSetBits(&DmaBitmap[i]);
1907cda1ed2SHervé Poussineau     }
19167141abeSHervé Poussineau 
19267141abeSHervé Poussineau     /* Allocate memory to store requirements */
19367141abeSHervé Poussineau     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
19467141abeSHervé Poussineau                + ResourceCount * sizeof(IO_RESOURCE_DESCRIPTOR);
195*66c19575SDmitry Borisov     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
19667141abeSHervé Poussineau     if (!RequirementsList)
19767141abeSHervé Poussineau         return STATUS_NO_MEMORY;
19867141abeSHervé Poussineau 
19967141abeSHervé Poussineau     RequirementsList->ListSize = ListSize;
20067141abeSHervé Poussineau     RequirementsList->InterfaceType = Isa;
20167141abeSHervé Poussineau     RequirementsList->AlternativeLists = 1;
20267141abeSHervé Poussineau 
20367141abeSHervé Poussineau     RequirementsList->List[0].Version = 1;
20467141abeSHervé Poussineau     RequirementsList->List[0].Revision = 1;
20567141abeSHervé Poussineau     RequirementsList->List[0].Count = ResourceCount;
20667141abeSHervé Poussineau 
20767141abeSHervé Poussineau     /* Store requirements */
20867141abeSHervé Poussineau     Descriptor = RequirementsList->List[0].Descriptors;
2098f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
21067141abeSHervé Poussineau     {
21167141abeSHervé Poussineau         if (!LogDev->Io[i].Description.Length)
21267141abeSHervé Poussineau             break;
2138f44930fSDmitry Borisov 
21467141abeSHervé Poussineau         DPRINT("Device.Io[%d].Information = 0x%02x\n", i, LogDev->Io[i].Description.Information);
21567141abeSHervé Poussineau         DPRINT("Device.Io[%d].Minimum = 0x%02x\n", i, LogDev->Io[i].Description.Minimum);
21667141abeSHervé Poussineau         DPRINT("Device.Io[%d].Maximum = 0x%02x\n", i, LogDev->Io[i].Description.Maximum);
21767141abeSHervé Poussineau         DPRINT("Device.Io[%d].Alignment = 0x%02x\n", i, LogDev->Io[i].Description.Alignment);
21867141abeSHervé Poussineau         DPRINT("Device.Io[%d].Length = 0x%02x\n", i, LogDev->Io[i].Description.Length);
2198f44930fSDmitry Borisov 
22067141abeSHervé Poussineau         Descriptor->Type = CmResourceTypePort;
22167141abeSHervé Poussineau         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
22267141abeSHervé Poussineau         if (LogDev->Io[i].Description.Information & 0x1)
22367141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
22467141abeSHervé Poussineau         else
22567141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
22667141abeSHervé Poussineau         Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
22767141abeSHervé Poussineau         Descriptor->u.Port.Alignment = LogDev->Io[i].Description.Alignment;
22867141abeSHervé Poussineau         Descriptor->u.Port.MinimumAddress.LowPart = LogDev->Io[i].Description.Minimum;
2298f44930fSDmitry Borisov         Descriptor->u.Port.MaximumAddress.LowPart =
2308f44930fSDmitry Borisov             LogDev->Io[i].Description.Maximum + LogDev->Io[i].Description.Length - 1;
23167141abeSHervé Poussineau         Descriptor++;
23267141abeSHervé Poussineau     }
2338f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
23467141abeSHervé Poussineau     {
23567141abeSHervé Poussineau         if (!LogDev->Irq[i].Description.Mask)
23667141abeSHervé Poussineau             break;
2378f44930fSDmitry Borisov 
23867141abeSHervé Poussineau         DPRINT("Device.Irq[%d].Mask = 0x%02x\n", i, LogDev->Irq[i].Description.Mask);
23967141abeSHervé Poussineau         DPRINT("Device.Irq[%d].Information = 0x%02x\n", i, LogDev->Irq[i].Description.Information);
2408f44930fSDmitry Borisov 
24167141abeSHervé Poussineau         for (j = 0; j < 15; j++)
24267141abeSHervé Poussineau         {
24367141abeSHervé Poussineau             if (!RtlCheckBit(&IrqBitmap[i], j))
24467141abeSHervé Poussineau                 continue;
2458f44930fSDmitry Borisov 
24667141abeSHervé Poussineau             if (FirstIrq)
24767141abeSHervé Poussineau                 FirstIrq = FALSE;
24867141abeSHervé Poussineau             else
24967141abeSHervé Poussineau                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
25067141abeSHervé Poussineau             Descriptor->Type = CmResourceTypeInterrupt;
25167141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
25267141abeSHervé Poussineau             Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j;
25367141abeSHervé Poussineau             Descriptor++;
2548f44930fSDmitry Borisov 
25567141abeSHervé Poussineau             if (LogDev->Irq[i].Description.Information & 0x4)
25667141abeSHervé Poussineau             {
25767141abeSHervé Poussineau                 /* Level interrupt */
25867141abeSHervé Poussineau                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
25967141abeSHervé Poussineau                 Descriptor->Type = CmResourceTypeInterrupt;
26067141abeSHervé Poussineau                 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
26167141abeSHervé Poussineau                 Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j;
26267141abeSHervé Poussineau                 Descriptor++;
26367141abeSHervé Poussineau             }
26467141abeSHervé Poussineau         }
26567141abeSHervé Poussineau     }
2668f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
2677cda1ed2SHervé Poussineau     {
2687cda1ed2SHervé Poussineau         if (!LogDev->Dma[i].Description.Mask)
2697cda1ed2SHervé Poussineau             break;
2708f44930fSDmitry Borisov 
2717cda1ed2SHervé Poussineau         DPRINT("Device.Dma[%d].Mask = 0x%02x\n", i, LogDev->Dma[i].Description.Mask);
2727cda1ed2SHervé Poussineau         DPRINT("Device.Dma[%d].Information = 0x%02x\n", i, LogDev->Dma[i].Description.Information);
2738f44930fSDmitry Borisov 
2747cda1ed2SHervé Poussineau         for (j = 0; j < 8; j++)
2757cda1ed2SHervé Poussineau         {
2767cda1ed2SHervé Poussineau             if (!RtlCheckBit(&DmaBitmap[i], j))
2777cda1ed2SHervé Poussineau                 continue;
2788f44930fSDmitry Borisov 
2797cda1ed2SHervé Poussineau             if (FirstDma)
2807cda1ed2SHervé Poussineau                 FirstDma = FALSE;
2817cda1ed2SHervé Poussineau             else
2827cda1ed2SHervé Poussineau                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
2837cda1ed2SHervé Poussineau             Descriptor->Type = CmResourceTypeDma;
2847cda1ed2SHervé Poussineau             switch (LogDev->Dma[i].Description.Information & 0x3)
2857cda1ed2SHervé Poussineau             {
2867cda1ed2SHervé Poussineau                 case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
2877cda1ed2SHervé Poussineau                 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
2887cda1ed2SHervé Poussineau                 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
2897cda1ed2SHervé Poussineau                 default: break;
2907cda1ed2SHervé Poussineau             }
2917cda1ed2SHervé Poussineau             if (LogDev->Dma[i].Description.Information & 0x4)
2927cda1ed2SHervé Poussineau                 Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
2937cda1ed2SHervé Poussineau             switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
2947cda1ed2SHervé Poussineau             {
2957cda1ed2SHervé Poussineau                 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
2967cda1ed2SHervé Poussineau                 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
2977cda1ed2SHervé Poussineau                 case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
2987cda1ed2SHervé Poussineau                 default: break;
2997cda1ed2SHervé Poussineau             }
3007cda1ed2SHervé Poussineau             Descriptor->u.Dma.MinimumChannel = Descriptor->u.Dma.MaximumChannel = j;
3017cda1ed2SHervé Poussineau             Descriptor++;
3027cda1ed2SHervé Poussineau         }
3037cda1ed2SHervé Poussineau     }
30467141abeSHervé Poussineau 
30567141abeSHervé Poussineau     PdoExt->RequirementsList = RequirementsList;
30667141abeSHervé Poussineau     return STATUS_SUCCESS;
30767141abeSHervé Poussineau }
30867141abeSHervé Poussineau 
30967141abeSHervé Poussineau static
31067141abeSHervé Poussineau NTSTATUS
31167141abeSHervé Poussineau NTAPI
3128f44930fSDmitry Borisov IsaPnpCreateLogicalDeviceResources(
3138f44930fSDmitry Borisov     _In_ PISAPNP_PDO_EXTENSION PdoExt)
31467141abeSHervé Poussineau {
31567141abeSHervé Poussineau     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
31667141abeSHervé Poussineau     ULONG ResourceCount = 0;
31767141abeSHervé Poussineau     ULONG ListSize, i;
31867141abeSHervé Poussineau     PCM_RESOURCE_LIST ResourceList;
31967141abeSHervé Poussineau     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
32067141abeSHervé Poussineau 
32167141abeSHervé Poussineau     /* Count number of required resources */
3228f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
32367141abeSHervé Poussineau     {
32467141abeSHervé Poussineau         if (LogDev->Io[i].CurrentBase)
32567141abeSHervé Poussineau             ResourceCount++;
32667141abeSHervé Poussineau         else
32767141abeSHervé Poussineau             break;
32867141abeSHervé Poussineau     }
3298f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
33067141abeSHervé Poussineau     {
33167141abeSHervé Poussineau         if (LogDev->Irq[i].CurrentNo)
33267141abeSHervé Poussineau             ResourceCount++;
33367141abeSHervé Poussineau         else
33467141abeSHervé Poussineau             break;
33567141abeSHervé Poussineau     }
3368f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
3377cda1ed2SHervé Poussineau     {
3387cda1ed2SHervé Poussineau         if (LogDev->Dma[i].CurrentChannel != 4)
3397cda1ed2SHervé Poussineau             ResourceCount++;
3407cda1ed2SHervé Poussineau         else
3417cda1ed2SHervé Poussineau             break;
3427cda1ed2SHervé Poussineau     }
34367141abeSHervé Poussineau     if (ResourceCount == 0)
34467141abeSHervé Poussineau         return STATUS_SUCCESS;
34567141abeSHervé Poussineau 
34667141abeSHervé Poussineau     /* Allocate memory to store resources */
34767141abeSHervé Poussineau     ListSize = sizeof(CM_RESOURCE_LIST)
34867141abeSHervé Poussineau                + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
349*66c19575SDmitry Borisov     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
35067141abeSHervé Poussineau     if (!ResourceList)
35167141abeSHervé Poussineau         return STATUS_NO_MEMORY;
35267141abeSHervé Poussineau 
35367141abeSHervé Poussineau     ResourceList->Count = 1;
35467141abeSHervé Poussineau     ResourceList->List[0].InterfaceType = Isa;
35567141abeSHervé Poussineau     ResourceList->List[0].PartialResourceList.Version = 1;
35667141abeSHervé Poussineau     ResourceList->List[0].PartialResourceList.Revision = 1;
35767141abeSHervé Poussineau     ResourceList->List[0].PartialResourceList.Count = ResourceCount;
35867141abeSHervé Poussineau 
35967141abeSHervé Poussineau     /* Store resources */
36067141abeSHervé Poussineau     ResourceCount = 0;
3618f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
36267141abeSHervé Poussineau     {
36367141abeSHervé Poussineau         if (!LogDev->Io[i].CurrentBase)
36467141abeSHervé Poussineau             continue;
3658f44930fSDmitry Borisov 
36667141abeSHervé Poussineau         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
36767141abeSHervé Poussineau         Descriptor->Type = CmResourceTypePort;
36867141abeSHervé Poussineau         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
36967141abeSHervé Poussineau         if (LogDev->Io[i].Description.Information & 0x1)
37067141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
37167141abeSHervé Poussineau         else
37267141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
37367141abeSHervé Poussineau         Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
37467141abeSHervé Poussineau         Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase;
37567141abeSHervé Poussineau     }
3768f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
37767141abeSHervé Poussineau     {
37867141abeSHervé Poussineau         if (!LogDev->Irq[i].CurrentNo)
37967141abeSHervé Poussineau             continue;
3808f44930fSDmitry Borisov 
38167141abeSHervé Poussineau         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
38267141abeSHervé Poussineau         Descriptor->Type = CmResourceTypeInterrupt;
38367141abeSHervé Poussineau         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
38467141abeSHervé Poussineau         if (LogDev->Irq[i].CurrentType & 0x01)
38567141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
38667141abeSHervé Poussineau         else
38767141abeSHervé Poussineau             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
38867141abeSHervé Poussineau         Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo;
38967141abeSHervé Poussineau         Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo;
39067141abeSHervé Poussineau         Descriptor->u.Interrupt.Affinity = -1;
39167141abeSHervé Poussineau     }
3928f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
3937cda1ed2SHervé Poussineau     {
3947cda1ed2SHervé Poussineau         if (LogDev->Dma[i].CurrentChannel == 4)
3957cda1ed2SHervé Poussineau             continue;
3968f44930fSDmitry Borisov 
3977cda1ed2SHervé Poussineau         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
3987cda1ed2SHervé Poussineau         Descriptor->Type = CmResourceTypeDma;
3997cda1ed2SHervé Poussineau         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
4007cda1ed2SHervé Poussineau         switch (LogDev->Dma[i].Description.Information & 0x3)
4017cda1ed2SHervé Poussineau         {
4027cda1ed2SHervé Poussineau             case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
4037cda1ed2SHervé Poussineau             case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8 | CM_RESOURCE_DMA_16; break;
4047cda1ed2SHervé Poussineau             case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
4057cda1ed2SHervé Poussineau             default: break;
4067cda1ed2SHervé Poussineau         }
4077cda1ed2SHervé Poussineau         if (LogDev->Dma[i].Description.Information & 0x4)
4087cda1ed2SHervé Poussineau             Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
4097cda1ed2SHervé Poussineau         switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
4107cda1ed2SHervé Poussineau         {
4117cda1ed2SHervé Poussineau             case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
4127cda1ed2SHervé Poussineau             case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
4137cda1ed2SHervé Poussineau             case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
4147cda1ed2SHervé Poussineau             default: break;
4157cda1ed2SHervé Poussineau         }
4167cda1ed2SHervé Poussineau         Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
4177cda1ed2SHervé Poussineau     }
41867141abeSHervé Poussineau 
41967141abeSHervé Poussineau     PdoExt->ResourceList = ResourceList;
42067141abeSHervé Poussineau     PdoExt->ResourceListSize = ListSize;
42167141abeSHervé Poussineau     return STATUS_SUCCESS;
42267141abeSHervé Poussineau }
42367141abeSHervé Poussineau 
424e0607fceSHervé Poussineau NTSTATUS
425e0607fceSHervé Poussineau NTAPI
42689aff07aSHervé Poussineau IsaPnpFillDeviceRelations(
4278f44930fSDmitry Borisov     _In_ PISAPNP_FDO_EXTENSION FdoExt,
4288f44930fSDmitry Borisov     _Inout_ PIRP Irp,
4298f44930fSDmitry Borisov     _In_ BOOLEAN IncludeDataPort)
43089aff07aSHervé Poussineau {
43189aff07aSHervé Poussineau     PISAPNP_PDO_EXTENSION PdoExt;
43289aff07aSHervé Poussineau     NTSTATUS Status = STATUS_SUCCESS;
43389aff07aSHervé Poussineau     PLIST_ENTRY CurrentEntry;
43489aff07aSHervé Poussineau     PISAPNP_LOGICAL_DEVICE IsaDevice;
43589aff07aSHervé Poussineau     PDEVICE_RELATIONS DeviceRelations;
43689aff07aSHervé Poussineau     ULONG i = 0;
43789aff07aSHervé Poussineau 
43889aff07aSHervé Poussineau     DeviceRelations = ExAllocatePool(NonPagedPool,
43989aff07aSHervé Poussineau                                      sizeof(DEVICE_RELATIONS) + sizeof(DEVICE_OBJECT) * FdoExt->DeviceCount);
44089aff07aSHervé Poussineau     if (!DeviceRelations)
44189aff07aSHervé Poussineau     {
44289aff07aSHervé Poussineau         return STATUS_NO_MEMORY;
44389aff07aSHervé Poussineau     }
44489aff07aSHervé Poussineau 
445c4813f73SHervé Poussineau     if (IncludeDataPort)
446c4813f73SHervé Poussineau     {
4478f44930fSDmitry Borisov         DeviceRelations->Objects[i++] = FdoExt->ReadPortPdo;
4488f44930fSDmitry Borisov         ObReferenceObject(FdoExt->ReadPortPdo);
449c4813f73SHervé Poussineau     }
450c4813f73SHervé Poussineau 
45189aff07aSHervé Poussineau     CurrentEntry = FdoExt->DeviceListHead.Flink;
45289aff07aSHervé Poussineau     while (CurrentEntry != &FdoExt->DeviceListHead)
45389aff07aSHervé Poussineau     {
4548f44930fSDmitry Borisov         IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
45589aff07aSHervé Poussineau 
45689aff07aSHervé Poussineau         if (!IsaDevice->Pdo)
45789aff07aSHervé Poussineau         {
45889aff07aSHervé Poussineau             Status = IoCreateDevice(FdoExt->DriverObject,
45989aff07aSHervé Poussineau                                     sizeof(ISAPNP_PDO_EXTENSION),
46089aff07aSHervé Poussineau                                     NULL,
46189aff07aSHervé Poussineau                                     FILE_DEVICE_CONTROLLER,
46289aff07aSHervé Poussineau                                     FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
46389aff07aSHervé Poussineau                                     FALSE,
46489aff07aSHervé Poussineau                                     &IsaDevice->Pdo);
46589aff07aSHervé Poussineau             if (!NT_SUCCESS(Status))
46689aff07aSHervé Poussineau             {
46789aff07aSHervé Poussineau                 break;
46889aff07aSHervé Poussineau             }
46989aff07aSHervé Poussineau 
47089aff07aSHervé Poussineau             IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
47189aff07aSHervé Poussineau 
47289aff07aSHervé Poussineau             //Device->Pdo->Flags |= DO_POWER_PAGABLE;
47389aff07aSHervé Poussineau 
4748f44930fSDmitry Borisov             PdoExt = IsaDevice->Pdo->DeviceExtension;
47589aff07aSHervé Poussineau 
47689aff07aSHervé Poussineau             RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
47789aff07aSHervé Poussineau 
47889aff07aSHervé Poussineau             PdoExt->Common.IsFdo = FALSE;
47989aff07aSHervé Poussineau             PdoExt->Common.Self = IsaDevice->Pdo;
48089aff07aSHervé Poussineau             PdoExt->Common.State = dsStopped;
48189aff07aSHervé Poussineau             PdoExt->IsaPnpDevice = IsaDevice;
4822fe644dcSHervé Poussineau             PdoExt->FdoExt = FdoExt;
483e0607fceSHervé Poussineau 
484e0607fceSHervé Poussineau             Status = IsaFdoCreateDeviceIDs(PdoExt);
48567141abeSHervé Poussineau 
48667141abeSHervé Poussineau             if (NT_SUCCESS(Status))
4878f44930fSDmitry Borisov                 Status = IsaPnpCreateLogicalDeviceRequirements(PdoExt);
48867141abeSHervé Poussineau 
48967141abeSHervé Poussineau             if (NT_SUCCESS(Status))
4908f44930fSDmitry Borisov                 Status = IsaPnpCreateLogicalDeviceResources(PdoExt);
49167141abeSHervé Poussineau 
492e0607fceSHervé Poussineau             if (!NT_SUCCESS(Status))
493e0607fceSHervé Poussineau             {
494e0607fceSHervé Poussineau                 IoDeleteDevice(IsaDevice->Pdo);
495e0607fceSHervé Poussineau                 IsaDevice->Pdo = NULL;
496e0607fceSHervé Poussineau                 break;
497e0607fceSHervé Poussineau             }
49889aff07aSHervé Poussineau         }
49989aff07aSHervé Poussineau         DeviceRelations->Objects[i++] = IsaDevice->Pdo;
50089aff07aSHervé Poussineau 
50189aff07aSHervé Poussineau         ObReferenceObject(IsaDevice->Pdo);
50289aff07aSHervé Poussineau 
50389aff07aSHervé Poussineau         CurrentEntry = CurrentEntry->Flink;
50489aff07aSHervé Poussineau     }
50589aff07aSHervé Poussineau 
50689aff07aSHervé Poussineau     DeviceRelations->Count = i;
50789aff07aSHervé Poussineau 
50889aff07aSHervé Poussineau     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
50989aff07aSHervé Poussineau 
51089aff07aSHervé Poussineau     return Status;
51189aff07aSHervé Poussineau }
51289aff07aSHervé Poussineau 
513c2c66affSColin Finck static IO_COMPLETION_ROUTINE ForwardIrpCompletion;
514c2c66affSColin Finck 
515c2c66affSColin Finck static
516c2c66affSColin Finck NTSTATUS
517c2c66affSColin Finck NTAPI
518c2c66affSColin Finck ForwardIrpCompletion(
519c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject,
520c2c66affSColin Finck     IN PIRP Irp,
521c2c66affSColin Finck     IN PVOID Context)
522c2c66affSColin Finck {
523c2c66affSColin Finck     UNREFERENCED_PARAMETER(DeviceObject);
524c2c66affSColin Finck 
525c2c66affSColin Finck     if (Irp->PendingReturned)
526c2c66affSColin Finck         KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
527c2c66affSColin Finck 
528c2c66affSColin Finck     return STATUS_MORE_PROCESSING_REQUIRED;
529c2c66affSColin Finck }
530c2c66affSColin Finck 
531c2c66affSColin Finck NTSTATUS
532c2c66affSColin Finck NTAPI
533c2c66affSColin Finck IsaForwardIrpSynchronous(
534c2c66affSColin Finck     IN PISAPNP_FDO_EXTENSION FdoExt,
535c2c66affSColin Finck     IN PIRP Irp)
536c2c66affSColin Finck {
537c2c66affSColin Finck     KEVENT Event;
538c2c66affSColin Finck     NTSTATUS Status;
539c2c66affSColin Finck 
540c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
541c2c66affSColin Finck     IoCopyCurrentIrpStackLocationToNext(Irp);
542c2c66affSColin Finck 
543c2c66affSColin Finck     IoSetCompletionRoutine(Irp, ForwardIrpCompletion, &Event, TRUE, TRUE, TRUE);
544c2c66affSColin Finck 
545c2c66affSColin Finck     Status = IoCallDriver(FdoExt->Ldo, Irp);
546c2c66affSColin Finck     if (Status == STATUS_PENDING)
547c2c66affSColin Finck     {
548c2c66affSColin Finck         Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
549c2c66affSColin Finck         if (NT_SUCCESS(Status))
550c2c66affSColin Finck             Status = Irp->IoStatus.Status;
551c2c66affSColin Finck     }
552c2c66affSColin Finck 
553c2c66affSColin Finck     return Status;
554c2c66affSColin Finck }
555c2c66affSColin Finck 
5568f44930fSDmitry Borisov _Dispatch_type_(IRP_MJ_CREATE)
5578f44930fSDmitry Borisov _Dispatch_type_(IRP_MJ_CLOSE)
558c2c66affSColin Finck static DRIVER_DISPATCH IsaCreateClose;
559c2c66affSColin Finck 
560c2c66affSColin Finck static
561c2c66affSColin Finck NTSTATUS
562c2c66affSColin Finck NTAPI
563c2c66affSColin Finck IsaCreateClose(
5648f44930fSDmitry Borisov     _In_ PDEVICE_OBJECT DeviceObject,
5658f44930fSDmitry Borisov     _Inout_ PIRP Irp)
566c2c66affSColin Finck {
567c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_SUCCESS;
568c2c66affSColin Finck     Irp->IoStatus.Information = FILE_OPENED;
569c2c66affSColin Finck 
570c2c66affSColin Finck     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
571c2c66affSColin Finck 
572c2c66affSColin Finck     IoCompleteRequest(Irp, IO_NO_INCREMENT);
573c2c66affSColin Finck 
574c2c66affSColin Finck     return STATUS_SUCCESS;
575c2c66affSColin Finck }
576c2c66affSColin Finck 
577c2c66affSColin Finck static DRIVER_DISPATCH IsaIoctl;
578c2c66affSColin Finck 
579c2c66affSColin Finck static
580c2c66affSColin Finck NTSTATUS
581c2c66affSColin Finck NTAPI
582c2c66affSColin Finck IsaIoctl(
583c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject,
584c2c66affSColin Finck     IN PIRP Irp)
585c2c66affSColin Finck {
586c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
587c2c66affSColin Finck     NTSTATUS Status;
588c2c66affSColin Finck 
589c2c66affSColin Finck     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
590c2c66affSColin Finck 
591c2c66affSColin Finck     switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
592c2c66affSColin Finck     {
593c2c66affSColin Finck         default:
594c2c66affSColin Finck             DPRINT1("Unknown ioctl code: %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
595c2c66affSColin Finck             Status = STATUS_NOT_SUPPORTED;
596c2c66affSColin Finck             break;
597c2c66affSColin Finck     }
598c2c66affSColin Finck 
599c2c66affSColin Finck     Irp->IoStatus.Status = Status;
600c2c66affSColin Finck     IoCompleteRequest(Irp, IO_NO_INCREMENT);
601c2c66affSColin Finck 
602c2c66affSColin Finck     return Status;
603c2c66affSColin Finck }
604c2c66affSColin Finck 
605c2c66affSColin Finck static DRIVER_DISPATCH IsaReadWrite;
606c2c66affSColin Finck 
607c2c66affSColin Finck static
608c2c66affSColin Finck NTSTATUS
609c2c66affSColin Finck NTAPI
610c2c66affSColin Finck IsaReadWrite(
611c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject,
612c2c66affSColin Finck     IN PIRP Irp)
613c2c66affSColin Finck {
614c2c66affSColin Finck     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
615c2c66affSColin Finck 
616c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
617c2c66affSColin Finck     Irp->IoStatus.Information = 0;
618c2c66affSColin Finck 
619c2c66affSColin Finck     IoCompleteRequest(Irp, IO_NO_INCREMENT);
620c2c66affSColin Finck 
621c2c66affSColin Finck     return STATUS_NOT_SUPPORTED;
622c2c66affSColin Finck }
623c2c66affSColin Finck 
624c2c66affSColin Finck static
625c2c66affSColin Finck NTSTATUS
626c2c66affSColin Finck NTAPI
627debec8c9SHervé Poussineau IsaPnpCreateReadPortDORequirements(
6288f44930fSDmitry Borisov     _In_ PISAPNP_PDO_EXTENSION PdoExt)
629debec8c9SHervé Poussineau {
630debec8c9SHervé Poussineau     ULONG ListSize, i;
631debec8c9SHervé Poussineau     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
632debec8c9SHervé Poussineau     PIO_RESOURCE_DESCRIPTOR Descriptor;
6338f44930fSDmitry Borisov     const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS,
6348f44930fSDmitry Borisov                             0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 };
635debec8c9SHervé Poussineau 
636debec8c9SHervé Poussineau     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
6378f44930fSDmitry Borisov                + 2 * RTL_NUMBER_OF(Ports) * sizeof(IO_RESOURCE_DESCRIPTOR);
638*66c19575SDmitry Borisov     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
639debec8c9SHervé Poussineau     if (!RequirementsList)
640debec8c9SHervé Poussineau         return STATUS_NO_MEMORY;
641debec8c9SHervé Poussineau 
642debec8c9SHervé Poussineau     RequirementsList->ListSize = ListSize;
643debec8c9SHervé Poussineau     RequirementsList->AlternativeLists = 1;
644debec8c9SHervé Poussineau 
645debec8c9SHervé Poussineau     RequirementsList->List[0].Version = 1;
646debec8c9SHervé Poussineau     RequirementsList->List[0].Revision = 1;
6478f44930fSDmitry Borisov     RequirementsList->List[0].Count = 2 * RTL_NUMBER_OF(Ports);
648debec8c9SHervé Poussineau 
6498f44930fSDmitry Borisov     for (i = 0; i < 2 * RTL_NUMBER_OF(Ports); i += 2)
650debec8c9SHervé Poussineau     {
651debec8c9SHervé Poussineau         Descriptor = &RequirementsList->List[0].Descriptors[i];
652debec8c9SHervé Poussineau 
653debec8c9SHervé Poussineau         /* Expected port */
654debec8c9SHervé Poussineau         Descriptor[0].Type = CmResourceTypePort;
655debec8c9SHervé Poussineau         Descriptor[0].ShareDisposition = CmResourceShareDeviceExclusive;
656debec8c9SHervé Poussineau         Descriptor[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
657debec8c9SHervé Poussineau         Descriptor[0].u.Port.Length = Ports[i / 2] & 1 ? 0x01 : 0x04;
658debec8c9SHervé Poussineau         Descriptor[0].u.Port.Alignment = 0x01;
659debec8c9SHervé Poussineau         Descriptor[0].u.Port.MinimumAddress.LowPart = Ports[i / 2];
660debec8c9SHervé Poussineau         Descriptor[0].u.Port.MaximumAddress.LowPart = Ports[i / 2] + Descriptor[0].u.Port.Length - 1;
661debec8c9SHervé Poussineau 
662debec8c9SHervé Poussineau         /* ... but mark it as optional */
663debec8c9SHervé Poussineau         Descriptor[1].Option = IO_RESOURCE_ALTERNATIVE;
664debec8c9SHervé Poussineau         Descriptor[1].Type = CmResourceTypePort;
665debec8c9SHervé Poussineau         Descriptor[1].ShareDisposition = CmResourceShareDeviceExclusive;
666debec8c9SHervé Poussineau         Descriptor[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
667debec8c9SHervé Poussineau         Descriptor[1].u.Port.Alignment = 0x01;
668debec8c9SHervé Poussineau     }
669debec8c9SHervé Poussineau 
670debec8c9SHervé Poussineau     PdoExt->RequirementsList = RequirementsList;
671debec8c9SHervé Poussineau     return STATUS_SUCCESS;
672debec8c9SHervé Poussineau }
673debec8c9SHervé Poussineau 
674debec8c9SHervé Poussineau static
675debec8c9SHervé Poussineau NTSTATUS
676debec8c9SHervé Poussineau NTAPI
67761c1079aSHervé Poussineau IsaPnpCreateReadPortDOResources(
6788f44930fSDmitry Borisov     _In_ PISAPNP_PDO_EXTENSION PdoExt)
67961c1079aSHervé Poussineau {
6808f44930fSDmitry Borisov     const USHORT Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS };
68161c1079aSHervé Poussineau     ULONG ListSize, i;
68261c1079aSHervé Poussineau     PCM_RESOURCE_LIST ResourceList;
68361c1079aSHervé Poussineau     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
68461c1079aSHervé Poussineau 
6858f44930fSDmitry Borisov     ListSize = sizeof(CM_RESOURCE_LIST) +
6868f44930fSDmitry Borisov                sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (RTL_NUMBER_OF(Ports) - 1);
687*66c19575SDmitry Borisov     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
68861c1079aSHervé Poussineau     if (!ResourceList)
68961c1079aSHervé Poussineau         return STATUS_NO_MEMORY;
69061c1079aSHervé Poussineau 
69161c1079aSHervé Poussineau     ResourceList->Count = 1;
69261c1079aSHervé Poussineau     ResourceList->List[0].InterfaceType = Internal;
69361c1079aSHervé Poussineau     ResourceList->List[0].PartialResourceList.Version = 1;
69461c1079aSHervé Poussineau     ResourceList->List[0].PartialResourceList.Revision = 1;
6958f44930fSDmitry Borisov     ResourceList->List[0].PartialResourceList.Count = RTL_NUMBER_OF(Ports);
69661c1079aSHervé Poussineau 
6978f44930fSDmitry Borisov     for (i = 0; i < RTL_NUMBER_OF(Ports); i++)
69861c1079aSHervé Poussineau     {
69961c1079aSHervé Poussineau         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
70061c1079aSHervé Poussineau         Descriptor->Type = CmResourceTypePort;
70161c1079aSHervé Poussineau         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
70261c1079aSHervé Poussineau         Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
70361c1079aSHervé Poussineau         Descriptor->u.Port.Length = 0x01;
70461c1079aSHervé Poussineau         Descriptor->u.Port.Start.LowPart = Ports[i];
70561c1079aSHervé Poussineau     }
70661c1079aSHervé Poussineau 
70761c1079aSHervé Poussineau     PdoExt->ResourceList = ResourceList;
70861c1079aSHervé Poussineau     PdoExt->ResourceListSize = ListSize;
70961c1079aSHervé Poussineau     return STATUS_SUCCESS;
71061c1079aSHervé Poussineau }
71161c1079aSHervé Poussineau 
71261c1079aSHervé Poussineau static
71361c1079aSHervé Poussineau NTSTATUS
71461c1079aSHervé Poussineau NTAPI
7158f44930fSDmitry Borisov IsaPnpCreateReadPortDO(
7168f44930fSDmitry Borisov     _In_ PISAPNP_FDO_EXTENSION FdoExt)
717c4813f73SHervé Poussineau {
718c4813f73SHervé Poussineau     UNICODE_STRING DeviceID = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0");
719c4813f73SHervé Poussineau     UNICODE_STRING HardwareIDs = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0\0");
72042724f47SHervé Poussineau     UNICODE_STRING CompatibleIDs = RTL_CONSTANT_STRING(L"\0\0");
721c4813f73SHervé Poussineau     UNICODE_STRING InstanceID = RTL_CONSTANT_STRING(L"0\0");
722c4813f73SHervé Poussineau     PISAPNP_PDO_EXTENSION PdoExt;
723c4813f73SHervé Poussineau     NTSTATUS Status;
7248f44930fSDmitry Borisov 
725c4813f73SHervé Poussineau     Status = IoCreateDevice(FdoExt->DriverObject,
726c4813f73SHervé Poussineau                             sizeof(ISAPNP_PDO_EXTENSION),
727c4813f73SHervé Poussineau                             NULL,
728c4813f73SHervé Poussineau                             FILE_DEVICE_CONTROLLER,
729c4813f73SHervé Poussineau                             FILE_DEVICE_SECURE_OPEN,
730c4813f73SHervé Poussineau                             FALSE,
7318f44930fSDmitry Borisov                             &FdoExt->ReadPortPdo);
732c4813f73SHervé Poussineau     if (!NT_SUCCESS(Status))
733c4813f73SHervé Poussineau         return Status;
7348f44930fSDmitry Borisov 
7358f44930fSDmitry Borisov     PdoExt = FdoExt->ReadPortPdo->DeviceExtension;
736c4813f73SHervé Poussineau     RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
737c4813f73SHervé Poussineau     PdoExt->Common.IsFdo = FALSE;
7388f44930fSDmitry Borisov     PdoExt->Common.Self = FdoExt->ReadPortPdo;
739c4813f73SHervé Poussineau     PdoExt->Common.State = dsStopped;
7402fe644dcSHervé Poussineau     PdoExt->FdoExt = FdoExt;
741c4813f73SHervé Poussineau 
742c4813f73SHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(0,
743c4813f73SHervé Poussineau                                           &DeviceID,
744c4813f73SHervé Poussineau                                           &PdoExt->DeviceID);
745c4813f73SHervé Poussineau     if (!NT_SUCCESS(Status))
746c4813f73SHervé Poussineau         return Status;
747c4813f73SHervé Poussineau 
748c4813f73SHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(0,
749c4813f73SHervé Poussineau                                           &HardwareIDs,
750c4813f73SHervé Poussineau                                           &PdoExt->HardwareIDs);
751c4813f73SHervé Poussineau     if (!NT_SUCCESS(Status))
752c4813f73SHervé Poussineau         return Status;
753c4813f73SHervé Poussineau 
754c4813f73SHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(0,
75542724f47SHervé Poussineau                                           &CompatibleIDs,
75642724f47SHervé Poussineau                                           &PdoExt->CompatibleIDs);
75742724f47SHervé Poussineau     if (!NT_SUCCESS(Status))
75842724f47SHervé Poussineau         return Status;
75942724f47SHervé Poussineau 
76042724f47SHervé Poussineau     Status = IsaPnpDuplicateUnicodeString(0,
761c4813f73SHervé Poussineau                                           &InstanceID,
762c4813f73SHervé Poussineau                                           &PdoExt->InstanceID);
763c4813f73SHervé Poussineau     if (!NT_SUCCESS(Status))
764c4813f73SHervé Poussineau         return Status;
765c4813f73SHervé Poussineau 
766debec8c9SHervé Poussineau     Status = IsaPnpCreateReadPortDORequirements(PdoExt);
767debec8c9SHervé Poussineau     if (!NT_SUCCESS(Status))
768debec8c9SHervé Poussineau         return Status;
769debec8c9SHervé Poussineau 
77061c1079aSHervé Poussineau     Status = IsaPnpCreateReadPortDOResources(PdoExt);
77161c1079aSHervé Poussineau     if (!NT_SUCCESS(Status))
77261c1079aSHervé Poussineau         return Status;
77361c1079aSHervé Poussineau 
774c4813f73SHervé Poussineau     return Status;
775c4813f73SHervé Poussineau }
776c4813f73SHervé Poussineau 
777c4813f73SHervé Poussineau static
778c4813f73SHervé Poussineau NTSTATUS
779c4813f73SHervé Poussineau NTAPI
780c2c66affSColin Finck IsaAddDevice(
7818f44930fSDmitry Borisov     _In_ PDRIVER_OBJECT DriverObject,
7828f44930fSDmitry Borisov     _In_ PDEVICE_OBJECT PhysicalDeviceObject)
783c2c66affSColin Finck {
784c2c66affSColin Finck     PDEVICE_OBJECT Fdo;
785c2c66affSColin Finck     PISAPNP_FDO_EXTENSION FdoExt;
786c2c66affSColin Finck     NTSTATUS Status;
787c2c66affSColin Finck 
788c2c66affSColin Finck     DPRINT("%s(%p, %p)\n", __FUNCTION__, DriverObject, PhysicalDeviceObject);
789c2c66affSColin Finck 
790c2c66affSColin Finck     Status = IoCreateDevice(DriverObject,
791c2c66affSColin Finck                             sizeof(*FdoExt),
792c2c66affSColin Finck                             NULL,
793c2c66affSColin Finck                             FILE_DEVICE_BUS_EXTENDER,
794c2c66affSColin Finck                             FILE_DEVICE_SECURE_OPEN,
795c2c66affSColin Finck                             TRUE,
796c2c66affSColin Finck                             &Fdo);
797c2c66affSColin Finck     if (!NT_SUCCESS(Status))
798c2c66affSColin Finck     {
7998f44930fSDmitry Borisov         DPRINT1("Failed to create FDO (0x%08lx)\n", Status);
800c2c66affSColin Finck         return Status;
801c2c66affSColin Finck     }
802c2c66affSColin Finck 
803c2c66affSColin Finck     FdoExt = Fdo->DeviceExtension;
804c2c66affSColin Finck     RtlZeroMemory(FdoExt, sizeof(*FdoExt));
805c2c66affSColin Finck 
806c2c66affSColin Finck     FdoExt->Common.Self = Fdo;
807c2c66affSColin Finck     FdoExt->Common.IsFdo = TRUE;
808c2c66affSColin Finck     FdoExt->Common.State = dsStopped;
8097a98d28dSHervé Poussineau     FdoExt->DriverObject = DriverObject;
810c2c66affSColin Finck     FdoExt->Pdo = PhysicalDeviceObject;
811c2c66affSColin Finck     FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo,
812c2c66affSColin Finck                                               PhysicalDeviceObject);
813c2c66affSColin Finck 
814c2c66affSColin Finck     InitializeListHead(&FdoExt->DeviceListHead);
815c2c66affSColin Finck     KeInitializeSpinLock(&FdoExt->Lock);
816c2c66affSColin Finck 
817c4813f73SHervé Poussineau     Status = IsaPnpCreateReadPortDO(FdoExt);
818c4813f73SHervé Poussineau     if (!NT_SUCCESS(Status))
819c4813f73SHervé Poussineau         return Status;
820c4813f73SHervé Poussineau 
821c2c66affSColin Finck     Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
8228f44930fSDmitry Borisov     FdoExt->ReadPortPdo->Flags &= ~DO_DEVICE_INITIALIZING;
823c2c66affSColin Finck 
824c2c66affSColin Finck     return STATUS_SUCCESS;
825c2c66affSColin Finck }
826c2c66affSColin Finck 
8278f44930fSDmitry Borisov _Dispatch_type_(IRP_MJ_POWER)
8289df05ba4SHervé Poussineau DRIVER_DISPATCH IsaPower;
8298f44930fSDmitry Borisov 
8309df05ba4SHervé Poussineau NTSTATUS
8319df05ba4SHervé Poussineau NTAPI
8329df05ba4SHervé Poussineau IsaPower(
8338f44930fSDmitry Borisov     _In_ PDEVICE_OBJECT DeviceObject,
8348f44930fSDmitry Borisov     _Inout_ PIRP Irp)
8359df05ba4SHervé Poussineau {
8369df05ba4SHervé Poussineau     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
8379df05ba4SHervé Poussineau     NTSTATUS Status;
8389df05ba4SHervé Poussineau 
8399df05ba4SHervé Poussineau     if (!DevExt->IsFdo)
8409df05ba4SHervé Poussineau     {
8419df05ba4SHervé Poussineau         Status = Irp->IoStatus.Status;
8429df05ba4SHervé Poussineau         IoCompleteRequest(Irp, IO_NO_INCREMENT);
8439df05ba4SHervé Poussineau         return Status;
8449df05ba4SHervé Poussineau     }
8459df05ba4SHervé Poussineau 
8469df05ba4SHervé Poussineau     PoStartNextPowerIrp(Irp);
8479df05ba4SHervé Poussineau     IoSkipCurrentIrpStackLocation(Irp);
8489df05ba4SHervé Poussineau     return PoCallDriver(((PISAPNP_FDO_EXTENSION)DevExt)->Ldo, Irp);
8499df05ba4SHervé Poussineau }
8509df05ba4SHervé Poussineau 
8518f44930fSDmitry Borisov _Dispatch_type_(IRP_MJ_PNP)
852c2c66affSColin Finck static DRIVER_DISPATCH IsaPnp;
853c2c66affSColin Finck 
854c2c66affSColin Finck static
855c2c66affSColin Finck NTSTATUS
856c2c66affSColin Finck NTAPI
857c2c66affSColin Finck IsaPnp(
8588f44930fSDmitry Borisov     _In_ PDEVICE_OBJECT DeviceObject,
8598f44930fSDmitry Borisov     _Inout_ PIRP Irp)
860c2c66affSColin Finck {
861c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
862c2c66affSColin Finck     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
863c2c66affSColin Finck 
864c2c66affSColin Finck     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
865c2c66affSColin Finck 
866c2c66affSColin Finck     if (DevExt->IsFdo)
8678f44930fSDmitry Borisov         return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt, Irp, IrpSp);
868c2c66affSColin Finck     else
8698f44930fSDmitry Borisov         return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt, Irp, IrpSp);
870c2c66affSColin Finck }
871c2c66affSColin Finck 
872c2c66affSColin Finck NTSTATUS
873c2c66affSColin Finck NTAPI
874c2c66affSColin Finck DriverEntry(
8758f44930fSDmitry Borisov     _In_ PDRIVER_OBJECT DriverObject,
8768f44930fSDmitry Borisov     _In_ PUNICODE_STRING RegistryPath)
877c2c66affSColin Finck {
878c2c66affSColin Finck     DPRINT("%s(%p, %wZ)\n", __FUNCTION__, DriverObject, RegistryPath);
879c2c66affSColin Finck 
880c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
881c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
882c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_READ] = IsaReadWrite;
883c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_WRITE] = IsaReadWrite;
884c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaIoctl;
885c2c66affSColin Finck     DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
8869df05ba4SHervé Poussineau     DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower;
887c2c66affSColin Finck     DriverObject->DriverExtension->AddDevice = IsaAddDevice;
888c2c66affSColin Finck 
889c2c66affSColin Finck     return STATUS_SUCCESS;
890c2c66affSColin Finck }
891c2c66affSColin Finck 
892c2c66affSColin Finck /* EOF */
893