xref: /reactos/drivers/bus/isapnp/pdo.c (revision 74ec94e1)
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 = FALSE;
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 = STATUS_INSUFFICIENT_RESOURCES;
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 && PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort)
213         {
214             PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
215             if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
216             {
217                 /* we detected some ISAPNP cards */
218                 FdoExt->ReadDataPort = ReadDataPort;
219                 KeAcquireSpinLock(&FdoExt->Lock, &OldIrql);
220                 Status = IsaHwFillDeviceList(FdoExt);
221                 KeReleaseSpinLock(&FdoExt->Lock, OldIrql);
222                 if (FdoExt->DeviceCount > 0)
223                 {
224                     IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
225                     IoInvalidateDeviceRelations(FdoExt->DataPortPdo, RemovalRelations);
226                 }
227             }
228             else
229             {
230                 /* mark read data port as started, even if no card has been detected */
231                 Status = STATUS_SUCCESS;
232             }
233         }
234     }
235     return Status;
236 }
237 
238 static
239 NTSTATUS
240 NTAPI
241 IsaPdoOnRepeaterComplete(
242     IN PDEVICE_OBJECT Tdo,
243     IN PIRP SubIrp,
244     PVOID NeedsVote)
245 {
246     PIO_STACK_LOCATION SubStack = IoGetCurrentIrpStackLocation(SubIrp);
247     PIRP Irp = (PIRP)SubStack->Parameters.Others.Argument1;
248     ObDereferenceObject(Tdo);
249 
250     if (SubIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
251     {
252         if (NeedsVote)
253         {
254             Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
255         }
256     }
257     else
258     {
259         Irp->IoStatus = SubIrp->IoStatus;
260     }
261 
262     IoFreeIrp(SubIrp);
263     IoCompleteRequest(Irp, IO_NO_INCREMENT);
264     return STATUS_MORE_PROCESSING_REQUIRED;
265 }
266 
267 NTSTATUS
268 NTAPI
269 IsaPdoRepeatRequest(
270     IN PISAPNP_PDO_EXTENSION PdoExt,
271     IN PIRP Irp,
272     IN BOOLEAN NeedsVote)
273 {
274     PDEVICE_OBJECT Fdo = PdoExt->FdoExt->Common.Self;
275     PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
276 
277     PDEVICE_OBJECT Tdo = IoGetAttachedDeviceReference(Fdo);
278     PIRP SubIrp = IoAllocateIrp(Tdo->StackSize + 1, FALSE);
279     PIO_STACK_LOCATION SubStack = IoGetNextIrpStackLocation(SubIrp);
280 
281     SubStack->DeviceObject = Tdo;
282     SubStack->Parameters.Others.Argument1 = (PVOID)Irp;
283 
284     IoSetNextIrpStackLocation(SubIrp);
285     SubStack = IoGetNextIrpStackLocation(SubIrp);
286     RtlCopyMemory(SubStack, Stack, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
287     SubStack->Control = 0;
288     IoSetCompletionRoutine(SubIrp, IsaPdoOnRepeaterComplete, (PVOID)(ULONG_PTR)NeedsVote, TRUE, TRUE, TRUE);
289 
290     SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
291     IoMarkIrpPending(Irp);
292     IoCallDriver(Tdo, SubIrp);
293     return STATUS_PENDING;
294 }
295 
296 NTSTATUS
297 NTAPI
298 IsaPdoPnp(
299     IN PISAPNP_PDO_EXTENSION PdoExt,
300     IN PIRP Irp,
301     IN PIO_STACK_LOCATION IrpSp)
302 {
303     NTSTATUS Status = Irp->IoStatus.Status;
304 
305     switch (IrpSp->MinorFunction)
306     {
307         case IRP_MN_START_DEVICE:
308             if (PdoExt->IsaPnpDevice)
309                 Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice);
310             else
311                 Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp);
312 
313             if (NT_SUCCESS(Status))
314                 PdoExt->Common.State = dsStarted;
315             break;
316 
317         case IRP_MN_STOP_DEVICE:
318             if (PdoExt->IsaPnpDevice)
319                 Status = IsaHwDeactivateDevice(PdoExt->IsaPnpDevice);
320             else
321                 Status = STATUS_SUCCESS;
322 
323             if (NT_SUCCESS(Status))
324                 PdoExt->Common.State = dsStopped;
325             break;
326 
327         case IRP_MN_QUERY_DEVICE_RELATIONS:
328             Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp);
329             break;
330 
331         case IRP_MN_QUERY_CAPABILITIES:
332             Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp);
333             break;
334 
335         case IRP_MN_QUERY_PNP_DEVICE_STATE:
336             if (PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo)
337                 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp, IrpSp);
338             break;
339 
340         case IRP_MN_QUERY_RESOURCES:
341             Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp);
342             break;
343 
344         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
345             Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp);
346             break;
347 
348         case IRP_MN_QUERY_ID:
349             Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
350             break;
351 
352         case IRP_MN_QUERY_REMOVE_DEVICE:
353         case IRP_MN_REMOVE_DEVICE:
354         case IRP_MN_CANCEL_REMOVE_DEVICE:
355         case IRP_MN_QUERY_STOP_DEVICE:
356         case IRP_MN_CANCEL_STOP_DEVICE:
357         case IRP_MN_QUERY_DEVICE_TEXT:
358         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
359         case IRP_MN_SURPRISE_REMOVAL:
360             Status = STATUS_SUCCESS;
361             break;
362 
363         case IRP_MN_READ_CONFIG:
364         case IRP_MN_WRITE_CONFIG:
365         case IRP_MN_EJECT:
366         case IRP_MN_SET_LOCK:
367         case IRP_MN_QUERY_BUS_INFORMATION:
368         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
369             return IsaPdoRepeatRequest(PdoExt, Irp, TRUE);
370 
371         default:
372             DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction);
373             break;
374     }
375 
376     Irp->IoStatus.Status = Status;
377     IoCompleteRequest(Irp, IO_NO_INCREMENT);
378 
379     return Status;
380 }
381