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 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 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 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 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 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 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 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 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 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 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 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