xref: /reactos/drivers/bus/isapnp/pdo.c (revision 019f21ee)
1 /*
2  * PROJECT:         ReactOS ISA PnP Bus driver
3  * FILE:            pdo.c
4  * PURPOSE:         PDO-specific code
5  * PROGRAMMERS:     Cameron Gutman (cameron.gutman@reactos.org)
6  *                  Hervé Poussineau
7  */
8 
9 #include <isapnp.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 NTSTATUS
15 NTAPI
16 IsaPdoQueryDeviceRelations(
17     IN PISAPNP_PDO_EXTENSION PdoExt,
18     IN PIRP Irp,
19     IN PIO_STACK_LOCATION IrpSp)
20 {
21     PDEVICE_RELATIONS DeviceRelations;
22 
23     if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations &&
24         PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo)
25     {
26         return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE);
27     }
28 
29     if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
30         return Irp->IoStatus.Status;
31 
32     DeviceRelations = ExAllocatePool(PagedPool, sizeof(*DeviceRelations));
33     if (!DeviceRelations)
34         return STATUS_NO_MEMORY;
35 
36     DeviceRelations->Count = 1;
37     DeviceRelations->Objects[0] = PdoExt->Common.Self;
38     ObReferenceObject(PdoExt->Common.Self);
39 
40     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
41 
42     return STATUS_SUCCESS;
43 }
44 
45 NTSTATUS
46 NTAPI
47 IsaPdoQueryCapabilities(
48     IN PISAPNP_PDO_EXTENSION PdoExt,
49     IN PIRP Irp,
50     IN PIO_STACK_LOCATION IrpSp)
51 {
52     PDEVICE_CAPABILITIES DeviceCapabilities;
53     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
54     ULONG i;
55 
56     DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
57     if (DeviceCapabilities->Version != 1)
58         return STATUS_REVISION_MISMATCH;
59 
60     if (LogDev)
61     {
62         DeviceCapabilities->UniqueID = TRUE;
63         DeviceCapabilities->Address = LogDev->CSN;
64     }
65     else
66     {
67         DeviceCapabilities->UniqueID = TRUE;
68         DeviceCapabilities->RawDeviceOK = TRUE;
69         DeviceCapabilities->SilentInstall = TRUE;
70     }
71 
72     for (i = 0; i < POWER_SYSTEM_MAXIMUM; i++)
73         DeviceCapabilities->DeviceState[i] = PowerDeviceD3;
74     DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
75 
76     return STATUS_SUCCESS;
77 }
78 
79 NTSTATUS
80 NTAPI
81 IsaPdoQueryPnpDeviceState(
82     IN PISAPNP_PDO_EXTENSION PdoExt,
83     IN PIRP Irp,
84     IN PIO_STACK_LOCATION IrpSp)
85 {
86     Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
87     return STATUS_SUCCESS;
88 }
89 
90 NTSTATUS
91 NTAPI
92 IsaPdoQueryId(
93     IN PISAPNP_PDO_EXTENSION PdoExt,
94     IN PIRP Irp,
95     IN PIO_STACK_LOCATION IrpSp)
96 {
97     PUNICODE_STRING Source;
98     PWCHAR Buffer;
99 
100     switch (IrpSp->Parameters.QueryId.IdType)
101     {
102         case BusQueryDeviceID:
103             DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
104             Source = &PdoExt->DeviceID;
105             break;
106 
107         case BusQueryHardwareIDs:
108             DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
109             Source = &PdoExt->HardwareIDs;
110             break;
111 
112         case BusQueryCompatibleIDs:
113             DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
114             Source = &PdoExt->CompatibleIDs;
115             break;
116 
117         case BusQueryInstanceID:
118             DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
119             Source = &PdoExt->InstanceID;
120             break;
121 
122         default:
123           DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n",
124                   IrpSp->Parameters.QueryId.IdType);
125           return Irp->IoStatus.Status;
126     }
127 
128     if (!Source->Buffer)
129         return Irp->IoStatus.Status;
130 
131     Buffer = ExAllocatePool(PagedPool, Source->MaximumLength);
132     if (!Buffer)
133         return STATUS_NO_MEMORY;
134 
135     RtlCopyMemory(Buffer, Source->Buffer, Source->MaximumLength);
136     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
137     return STATUS_SUCCESS;
138 }
139 
140 NTSTATUS
141 NTAPI
142 IsaPdoQueryResources(
143     IN PISAPNP_PDO_EXTENSION PdoExt,
144     IN PIRP Irp,
145     IN PIO_STACK_LOCATION IrpSp)
146 {
147     ULONG ListSize;
148     PCM_RESOURCE_LIST ResourceList;
149 
150     if (!PdoExt->ResourceList)
151         return Irp->IoStatus.Status;
152 
153     ListSize = PdoExt->ResourceListSize;
154     ResourceList = ExAllocatePool(PagedPool, ListSize);
155     if (!ResourceList)
156         return STATUS_NO_MEMORY;
157 
158     RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize);
159     Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
160     return STATUS_SUCCESS;
161 }
162 
163 NTSTATUS
164 NTAPI
165 IsaPdoQueryResourceRequirements(
166     IN PISAPNP_PDO_EXTENSION PdoExt,
167     IN PIRP Irp,
168     IN PIO_STACK_LOCATION IrpSp)
169 {
170     ULONG ListSize;
171     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
172 
173     if (!PdoExt->RequirementsList)
174         return Irp->IoStatus.Status;
175 
176     ListSize = PdoExt->RequirementsList->ListSize;
177     RequirementsList = ExAllocatePool(PagedPool, ListSize);
178     if (!RequirementsList)
179         return STATUS_NO_MEMORY;
180 
181     RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize);
182     Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
183     return STATUS_SUCCESS;
184 }
185 
186 static
187 NTSTATUS
188 NTAPI
189 IsaPdoStartReadPort(
190     IN PISAPNP_FDO_EXTENSION FdoExt,
191     IN PIO_STACK_LOCATION IrpSp)
192 {
193     PCM_RESOURCE_LIST ResourceList = IrpSp->Parameters.StartDevice.AllocatedResources;
194     NTSTATUS Status;
195     KIRQL OldIrql;
196     ULONG i;
197 
198     if (!ResourceList || ResourceList->Count != 1)
199     {
200         DPRINT1("No resource list (%p) or bad count (%d)\n", ResourceList, ResourceList ? ResourceList->Count : 0);
201         return STATUS_INSUFFICIENT_RESOURCES;
202     }
203     if (ResourceList->List[0].PartialResourceList.Version != 1
204      || ResourceList->List[0].PartialResourceList.Revision != 1)
205     {
206         DPRINT1("Bad resource list version (%d.%d)\n", ResourceList->List[0].PartialResourceList.Version, ResourceList->List[0].PartialResourceList.Revision);
207         return STATUS_REVISION_MISMATCH;
208     }
209     for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
210     {
211         PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
212         if (PartialDescriptor->Type == CmResourceTypePort)
213         {
214             PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
215             if (PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort && NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
216             {
217                 FdoExt->ReadDataPort = ReadDataPort;
218                 KeAcquireSpinLock(&FdoExt->Lock, &OldIrql);
219                 Status = IsaHwFillDeviceList(FdoExt);
220                 KeReleaseSpinLock(&FdoExt->Lock, OldIrql);
221                 if (FdoExt->DeviceCount > 0)
222                 {
223                     IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
224                     IoInvalidateDeviceRelations(FdoExt->DataPortPdo, RemovalRelations);
225                 }
226             }
227         }
228     }
229     return Status;
230 }
231 
232 static
233 NTSTATUS
234 NTAPI
235 IsaPdoOnRepeaterComplete(
236     IN PDEVICE_OBJECT Tdo,
237     IN PIRP SubIrp,
238     PVOID NeedsVote)
239 {
240     PIO_STACK_LOCATION SubStack = IoGetCurrentIrpStackLocation(SubIrp);
241     PIRP Irp = (PIRP)SubStack->Parameters.Others.Argument1;
242     ObDereferenceObject(Tdo);
243 
244     if (SubIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
245     {
246         if (NeedsVote)
247         {
248             Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
249         }
250     }
251     else
252     {
253         Irp->IoStatus = SubIrp->IoStatus;
254     }
255 
256     IoFreeIrp(SubIrp);
257     IoCompleteRequest(Irp, IO_NO_INCREMENT);
258     return STATUS_MORE_PROCESSING_REQUIRED;
259 }
260 
261 NTSTATUS
262 NTAPI
263 IsaPdoRepeatRequest(
264     IN PISAPNP_PDO_EXTENSION PdoExt,
265     IN PIRP Irp,
266     IN BOOLEAN NeedsVote)
267 {
268     PDEVICE_OBJECT Fdo = PdoExt->FdoExt->Common.Self;
269     PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
270 
271     PDEVICE_OBJECT Tdo = IoGetAttachedDeviceReference(Fdo);
272     PIRP SubIrp = IoAllocateIrp(Tdo->StackSize + 1, FALSE);
273     PIO_STACK_LOCATION SubStack = IoGetNextIrpStackLocation(SubIrp);
274 
275     SubStack->DeviceObject = Tdo;
276     SubStack->Parameters.Others.Argument1 = (PVOID)Irp;
277 
278     IoSetNextIrpStackLocation(SubIrp);
279     SubStack = IoGetNextIrpStackLocation(SubIrp);
280     RtlCopyMemory(SubStack, Stack, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
281     SubStack->Control = 0;
282     IoSetCompletionRoutine(SubIrp, IsaPdoOnRepeaterComplete, (PVOID)(ULONG_PTR)NeedsVote, TRUE, TRUE, TRUE);
283 
284     SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
285     IoMarkIrpPending(Irp);
286     IoCallDriver(Tdo, SubIrp);
287     return STATUS_PENDING;
288 }
289 
290 NTSTATUS
291 NTAPI
292 IsaPdoPnp(
293     IN PISAPNP_PDO_EXTENSION PdoExt,
294     IN PIRP Irp,
295     IN PIO_STACK_LOCATION IrpSp)
296 {
297     NTSTATUS Status = Irp->IoStatus.Status;
298 
299     switch (IrpSp->MinorFunction)
300     {
301         case IRP_MN_START_DEVICE:
302             if (PdoExt->IsaPnpDevice)
303                 Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice);
304             else
305                 Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp);
306 
307             if (NT_SUCCESS(Status))
308                 PdoExt->Common.State = dsStarted;
309             break;
310 
311         case IRP_MN_STOP_DEVICE:
312             if (PdoExt->IsaPnpDevice)
313                 Status = IsaHwDeactivateDevice(PdoExt->IsaPnpDevice);
314             else
315                 Status = STATUS_SUCCESS;
316 
317             if (NT_SUCCESS(Status))
318                 PdoExt->Common.State = dsStopped;
319             break;
320 
321         case IRP_MN_QUERY_DEVICE_RELATIONS:
322             Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp);
323             break;
324 
325         case IRP_MN_QUERY_CAPABILITIES:
326             Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp);
327             break;
328 
329         case IRP_MN_QUERY_PNP_DEVICE_STATE:
330             if (PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo)
331                 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp, IrpSp);
332             break;
333 
334         case IRP_MN_QUERY_RESOURCES:
335             Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp);
336             break;
337 
338         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
339             Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp);
340             break;
341 
342         case IRP_MN_QUERY_ID:
343             Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
344             break;
345 
346         case IRP_MN_QUERY_REMOVE_DEVICE:
347         case IRP_MN_REMOVE_DEVICE:
348         case IRP_MN_CANCEL_REMOVE_DEVICE:
349         case IRP_MN_QUERY_STOP_DEVICE:
350         case IRP_MN_CANCEL_STOP_DEVICE:
351         case IRP_MN_QUERY_DEVICE_TEXT:
352         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
353         case IRP_MN_SURPRISE_REMOVAL:
354             Status = STATUS_SUCCESS;
355             break;
356 
357         case IRP_MN_READ_CONFIG:
358         case IRP_MN_WRITE_CONFIG:
359         case IRP_MN_EJECT:
360         case IRP_MN_SET_LOCK:
361         case IRP_MN_QUERY_BUS_INFORMATION:
362         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
363             return IsaPdoRepeatRequest(PdoExt, Irp, TRUE);
364 
365         default:
366             DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction);
367             break;
368     }
369 
370     Irp->IoStatus.Status = Status;
371     IoCompleteRequest(Irp, IO_NO_INCREMENT);
372 
373     return Status;
374 }
375