1 /*
2 * PROJECT: PCI IDE bus driver extension
3 * LICENSE: See COPYING in the top level directory
4 * PURPOSE: IRP_MJ_PNP operations for FDOs
5 * COPYRIGHT: Copyright 2005 Hervé Poussineau <hpoussin@reactos.org>
6 * Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
7 */
8
9 #include "pciidex.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static
15 CODE_SEG("PAGE")
16 NTSTATUS
PciIdeXFdoParseResources(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PCM_RESOURCE_LIST ResourcesTranslated)17 PciIdeXFdoParseResources(
18 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
19 _In_ PCM_RESOURCE_LIST ResourcesTranslated)
20 {
21 PCM_PARTIAL_RESOURCE_DESCRIPTOR BusMasterDescriptor = NULL;
22 PVOID IoBase;
23 ULONG i;
24
25 PAGED_CODE();
26
27 if (!ResourcesTranslated)
28 return STATUS_INVALID_PARAMETER;
29
30 for (i = 0; i < ResourcesTranslated->List[0].PartialResourceList.Count; ++i)
31 {
32 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
33
34 Descriptor = &ResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
35 switch (Descriptor->Type)
36 {
37 case CmResourceTypePort:
38 case CmResourceTypeMemory:
39 {
40 switch (Descriptor->u.Port.Length)
41 {
42 /* Bus master port base */
43 case 16:
44 {
45 if (!BusMasterDescriptor)
46 BusMasterDescriptor = Descriptor;
47 break;
48 }
49
50 default:
51 break;
52 }
53 }
54
55 default:
56 break;
57 }
58 }
59
60 if (!BusMasterDescriptor)
61 return STATUS_DEVICE_CONFIGURATION_ERROR;
62
63 if ((BusMasterDescriptor->Type == CmResourceTypePort) &&
64 (BusMasterDescriptor->Flags & CM_RESOURCE_PORT_IO))
65 {
66 IoBase = (PVOID)(ULONG_PTR)BusMasterDescriptor->u.Port.Start.QuadPart;
67 }
68 else
69 {
70 IoBase = MmMapIoSpace(BusMasterDescriptor->u.Memory.Start, 16, MmNonCached);
71 if (!IoBase)
72 return STATUS_INSUFFICIENT_RESOURCES;
73
74 FdoExtension->IoBaseMapped = TRUE;
75 }
76 FdoExtension->BusMasterPortBase = IoBase;
77
78 return STATUS_SUCCESS;
79 }
80
81 static
82 CODE_SEG("PAGE")
83 NTSTATUS
PciIdeXFdoStartDevice(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIRP Irp)84 PciIdeXFdoStartDevice(
85 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
86 _In_ PIRP Irp)
87 {
88 NTSTATUS Status;
89 PIO_STACK_LOCATION IoStack;
90
91 PAGED_CODE();
92
93 if (!NT_VERIFY(IoForwardIrpSynchronously(FdoExtension->Ldo, Irp)))
94 {
95 return STATUS_UNSUCCESSFUL;
96 }
97 Status = Irp->IoStatus.Status;
98 if (!NT_SUCCESS(Status))
99 {
100 return Status;
101 }
102
103 IoStack = IoGetCurrentIrpStackLocation(Irp);
104
105 Status = PciIdeXFdoParseResources(FdoExtension,
106 IoStack->Parameters.StartDevice.AllocatedResourcesTranslated);
107 if (!NT_SUCCESS(Status))
108 {
109 DPRINT1("Failed to parse resources 0x%lx\n", Status);
110 return Status;
111 }
112
113 Status = PciIdeXStartMiniport(FdoExtension);
114 if (!NT_SUCCESS(Status))
115 {
116 DPRINT1("Miniport initialization failed 0x%lx\n", Status);
117 return Status;
118 }
119
120 return STATUS_SUCCESS;
121 }
122
123 static
124 CODE_SEG("PAGE")
125 VOID
PciIdeXFdoFreeResources(_In_ PFDO_DEVICE_EXTENSION FdoExtension)126 PciIdeXFdoFreeResources(
127 _In_ PFDO_DEVICE_EXTENSION FdoExtension)
128 {
129 PAGED_CODE();
130
131 if (FdoExtension->IoBaseMapped)
132 {
133 MmUnmapIoSpace(FdoExtension->BusMasterPortBase, 16);
134 FdoExtension->IoBaseMapped = FALSE;
135 }
136 }
137
138 static
139 CODE_SEG("PAGE")
140 NTSTATUS
PciIdeXFdoStopDevice(_In_ PFDO_DEVICE_EXTENSION FdoExtension)141 PciIdeXFdoStopDevice(
142 _In_ PFDO_DEVICE_EXTENSION FdoExtension)
143 {
144 PAGED_CODE();
145
146 PciIdeXFdoFreeResources(FdoExtension);
147
148 return STATUS_SUCCESS;
149 }
150
151 static
152 CODE_SEG("PAGE")
153 NTSTATUS
PciIdeXFdoRemoveDevice(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIRP Irp)154 PciIdeXFdoRemoveDevice(
155 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
156 _In_ PIRP Irp)
157 {
158 PPDO_DEVICE_EXTENSION PdoExtension;
159 NTSTATUS Status;
160 ULONG i;
161
162 PAGED_CODE();
163
164 PciIdeXFdoFreeResources(FdoExtension);
165
166 ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
167
168 for (i = 0; i < MAX_IDE_CHANNEL; ++i)
169 {
170 PdoExtension = FdoExtension->Channels[i];
171
172 if (PdoExtension)
173 {
174 IoDeleteDevice(PdoExtension->Common.Self);
175
176 FdoExtension->Channels[i] = NULL;
177 break;
178 }
179 }
180
181 ExReleaseFastMutex(&FdoExtension->DeviceSyncMutex);
182
183 Irp->IoStatus.Status = STATUS_SUCCESS;
184 IoSkipCurrentIrpStackLocation(Irp);
185 Status = IoCallDriver(FdoExtension->Ldo, Irp);
186
187 IoDetachDevice(FdoExtension->Ldo);
188 IoDeleteDevice(FdoExtension->Common.Self);
189
190 return Status;
191 }
192
193 static
194 CODE_SEG("PAGE")
195 NTSTATUS
PciIdeXFdoQueryPnpDeviceState(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIRP Irp)196 PciIdeXFdoQueryPnpDeviceState(
197 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
198 _In_ PIRP Irp)
199 {
200 PAGED_CODE();
201
202 if (FdoExtension->Common.PageFiles ||
203 FdoExtension->Common.HibernateFiles ||
204 FdoExtension->Common.DumpFiles)
205 {
206 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
207 }
208
209 Irp->IoStatus.Status = STATUS_SUCCESS;
210
211 return STATUS_SUCCESS;
212 }
213
214 static
215 CODE_SEG("PAGE")
216 PPDO_DEVICE_EXTENSION
PciIdeXPdoCreateDevice(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ ULONG ChannelNumber)217 PciIdeXPdoCreateDevice(
218 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
219 _In_ ULONG ChannelNumber)
220 {
221 NTSTATUS Status;
222 UNICODE_STRING DeviceName;
223 WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde999Channel9-FFF")];
224 PDEVICE_OBJECT Pdo;
225 PPDO_DEVICE_EXTENSION PdoExtension;
226 ULONG Alignment;
227 static ULONG DeviceNumber = 0;
228
229 PAGED_CODE();
230
231 Status = RtlStringCbPrintfW(DeviceNameBuffer,
232 sizeof(DeviceNameBuffer),
233 L"\\Device\\Ide\\PciIde%uChannel%u-%x",
234 FdoExtension->ControllerNumber,
235 ChannelNumber,
236 DeviceNumber++);
237 ASSERT(NT_SUCCESS(Status));
238 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
239
240 Status = IoCreateDevice(FdoExtension->Common.Self->DriverObject,
241 sizeof(*PdoExtension),
242 &DeviceName,
243 FILE_DEVICE_CONTROLLER,
244 FILE_DEVICE_SECURE_OPEN,
245 FALSE,
246 &Pdo);
247 if (!NT_SUCCESS(Status))
248 {
249 DPRINT1("Failed to create PDO 0x%lx\n", Status);
250 return NULL;
251 }
252
253 DPRINT("Created device object %p '%wZ'\n", Pdo, &DeviceName);
254
255 /* DMA buffers alignment */
256 Alignment = FdoExtension->Properties.AlignmentRequirement;
257 Alignment = max(Alignment, FdoExtension->Common.Self->AlignmentRequirement);
258 Alignment = max(Alignment, FILE_WORD_ALIGNMENT);
259 Pdo->AlignmentRequirement = Alignment;
260
261 PdoExtension = Pdo->DeviceExtension;
262
263 RtlZeroMemory(PdoExtension, sizeof(*PdoExtension));
264 PdoExtension->Common.Self = Pdo;
265 PdoExtension->Channel = ChannelNumber;
266 PdoExtension->ParentController = FdoExtension;
267
268 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
269 return PdoExtension;
270 }
271
272 static
273 CODE_SEG("PAGE")
274 NTSTATUS
PciIdeXFdoQueryBusRelations(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIRP Irp)275 PciIdeXFdoQueryBusRelations(
276 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
277 _In_ PIRP Irp)
278 {
279 PPDO_DEVICE_EXTENSION PdoExtension;
280 IDE_CHANNEL_STATE ChannelState;
281 PDEVICE_RELATIONS DeviceRelations;
282 ULONG i;
283
284 PAGED_CODE();
285
286 DeviceRelations = ExAllocatePoolWithTag(PagedPool,
287 FIELD_OFFSET(DEVICE_RELATIONS,
288 Objects[MAX_IDE_CHANNEL]),
289 TAG_PCIIDEX);
290 if (!DeviceRelations)
291 return STATUS_INSUFFICIENT_RESOURCES;
292
293 DeviceRelations->Count = 0;
294
295 ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
296
297 for (i = 0; i < MAX_IDE_CHANNEL; ++i)
298 {
299 PdoExtension = FdoExtension->Channels[i];
300
301 /* Ignore disabled channels */
302 ChannelState = PciIdeXChannelState(FdoExtension, i);
303 if (ChannelState == ChannelDisabled)
304 {
305 if (PdoExtension)
306 {
307 PdoExtension->ReportedMissing = TRUE;
308 }
309
310 DPRINT("Channel %lu is disabled\n", i);
311 continue;
312 }
313
314 /* Need to create a PDO */
315 if (!PdoExtension)
316 {
317 PdoExtension = PciIdeXPdoCreateDevice(FdoExtension, i);
318
319 FdoExtension->Channels[i] = PdoExtension;
320 }
321
322 if (PdoExtension && !PdoExtension->ReportedMissing)
323 {
324 DeviceRelations->Objects[DeviceRelations->Count++] = PdoExtension->Common.Self;
325 ObReferenceObject(PdoExtension->Common.Self);
326 }
327 }
328
329 ExReleaseFastMutex(&FdoExtension->DeviceSyncMutex);
330
331 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
332 return STATUS_SUCCESS;
333 }
334
335 static
336 CODE_SEG("PAGE")
337 NTSTATUS
PciIdeXFdoQueryDeviceUsageNotification(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIRP Irp)338 PciIdeXFdoQueryDeviceUsageNotification(
339 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
340 _In_ PIRP Irp)
341 {
342 PIO_STACK_LOCATION IoStack;
343 NTSTATUS Status;
344 volatile LONG* Counter;
345
346 PAGED_CODE();
347
348 if (!NT_VERIFY(IoForwardIrpSynchronously(FdoExtension->Ldo, Irp)))
349 {
350 return STATUS_UNSUCCESSFUL;
351 }
352 Status = Irp->IoStatus.Status;
353 if (!NT_SUCCESS(Status))
354 {
355 return Status;
356 }
357
358 IoStack = IoGetCurrentIrpStackLocation(Irp);
359 switch (IoStack->Parameters.UsageNotification.Type)
360 {
361 case DeviceUsageTypePaging:
362 Counter = &FdoExtension->Common.PageFiles;
363 break;
364
365 case DeviceUsageTypeHibernation:
366 Counter = &FdoExtension->Common.HibernateFiles;
367 break;
368
369 case DeviceUsageTypeDumpFile:
370 Counter = &FdoExtension->Common.DumpFiles;
371 break;
372
373 default:
374 return Status;
375 }
376
377 IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
378
379 return STATUS_SUCCESS;
380 }
381
382 static
383 CODE_SEG("PAGE")
384 NTSTATUS
PciIdeXFdoQueryInterface(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ PIO_STACK_LOCATION IoStack)385 PciIdeXFdoQueryInterface(
386 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
387 _In_ PIO_STACK_LOCATION IoStack)
388 {
389 PAGED_CODE();
390
391 if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
392 &GUID_TRANSLATOR_INTERFACE_STANDARD))
393 {
394 CM_RESOURCE_TYPE ResourceType;
395 ULONG BusNumber;
396
397 ResourceType = (ULONG_PTR)IoStack->Parameters.QueryInterface.InterfaceSpecificData;
398
399 /* In native mode the IDE controller does not use any legacy interrupt resources */
400 if (FdoExtension->InNativeMode ||
401 ResourceType != CmResourceTypeInterrupt ||
402 IoStack->Parameters.QueryInterface.Size < sizeof(TRANSLATOR_INTERFACE))
403 {
404 return STATUS_NOT_SUPPORTED;
405 }
406
407 return HalGetInterruptTranslator(PCIBus,
408 0,
409 InterfaceTypeUndefined,
410 sizeof(TRANSLATOR_INTERFACE),
411 IoStack->Parameters.QueryInterface.Version,
412 (PTRANSLATOR_INTERFACE)IoStack->
413 Parameters.QueryInterface.Interface,
414 &BusNumber);
415 }
416
417 return STATUS_NOT_SUPPORTED;
418 }
419
420 CODE_SEG("PAGE")
421 NTSTATUS
PciIdeXFdoDispatchPnp(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_Inout_ PIRP Irp)422 PciIdeXFdoDispatchPnp(
423 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
424 _Inout_ PIRP Irp)
425 {
426 PIO_STACK_LOCATION IoStack;
427 NTSTATUS Status;
428
429 PAGED_CODE();
430
431 IoStack = IoGetCurrentIrpStackLocation(Irp);
432 switch (IoStack->MinorFunction)
433 {
434 case IRP_MN_START_DEVICE:
435 {
436 Status = PciIdeXFdoStartDevice(FdoExtension, Irp);
437
438 Irp->IoStatus.Status = Status;
439 IoCompleteRequest(Irp, IO_NO_INCREMENT);
440
441 return Status;
442 }
443
444 case IRP_MN_STOP_DEVICE:
445 {
446 Status = PciIdeXFdoStopDevice(FdoExtension);
447 break;
448 }
449
450 case IRP_MN_REMOVE_DEVICE:
451 return PciIdeXFdoRemoveDevice(FdoExtension, Irp);
452
453 case IRP_MN_QUERY_PNP_DEVICE_STATE:
454 {
455 Status = PciIdeXFdoQueryPnpDeviceState(FdoExtension, Irp);
456 break;
457 }
458
459 case IRP_MN_QUERY_DEVICE_RELATIONS:
460 {
461 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
462 break;
463
464 Status = PciIdeXFdoQueryBusRelations(FdoExtension, Irp);
465 if (!NT_SUCCESS(Status))
466 {
467 Irp->IoStatus.Status = Status;
468 IoCompleteRequest(Irp, IO_NO_INCREMENT);
469
470 return Status;
471 }
472
473 Irp->IoStatus.Status = Status;
474 break;
475 }
476
477 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
478 {
479 Status = PciIdeXFdoQueryDeviceUsageNotification(FdoExtension, Irp);
480 break;
481 }
482
483 case IRP_MN_QUERY_INTERFACE:
484 {
485 Status = PciIdeXFdoQueryInterface(FdoExtension, IoStack);
486 if (Status == STATUS_NOT_SUPPORTED)
487 break;
488
489 Irp->IoStatus.Status = Status;
490 break;
491 }
492
493 case IRP_MN_QUERY_STOP_DEVICE:
494 case IRP_MN_QUERY_REMOVE_DEVICE:
495 case IRP_MN_SURPRISE_REMOVAL:
496 case IRP_MN_CANCEL_STOP_DEVICE:
497 case IRP_MN_CANCEL_REMOVE_DEVICE:
498 Irp->IoStatus.Status = STATUS_SUCCESS;
499 break;
500
501 default:
502 break;
503 }
504
505 IoSkipCurrentIrpStackLocation(Irp);
506 return IoCallDriver(FdoExtension->Ldo, Irp);
507 }
508