1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: PCI IDE bus driver extension 4 * FILE: drivers/storage/pciidex/fdo.c 5 * PURPOSE: IRP_MJ_PNP operations for FDOs 6 * PROGRAMMERS: Herv� Poussineau (hpoussin@reactos.org) 7 */ 8 9 #include "pciidex.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 #include <initguid.h> 15 #include <wdmguid.h> 16 17 static NTSTATUS 18 GetBusInterface( 19 IN PFDO_DEVICE_EXTENSION DeviceExtension) 20 { 21 PBUS_INTERFACE_STANDARD BusInterface = NULL; 22 KEVENT Event; 23 IO_STATUS_BLOCK IoStatus; 24 PIRP Irp; 25 PIO_STACK_LOCATION Stack; 26 NTSTATUS Status = STATUS_UNSUCCESSFUL; 27 28 if (DeviceExtension->BusInterface) 29 { 30 DPRINT("We already have the bus interface\n"); 31 goto cleanup; 32 } 33 34 BusInterface = ExAllocatePool(PagedPool, sizeof(BUS_INTERFACE_STANDARD)); 35 if (!BusInterface) 36 { 37 DPRINT("ExAllocatePool() failed\n"); 38 Status = STATUS_INSUFFICIENT_RESOURCES; 39 goto cleanup; 40 } 41 42 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 43 Irp = IoBuildSynchronousFsdRequest( 44 IRP_MJ_PNP, 45 DeviceExtension->LowerDevice, 46 NULL, 47 0, 48 NULL, 49 &Event, 50 &IoStatus); 51 if (!Irp) 52 { 53 DPRINT("IoBuildSynchronousFsdRequest() failed\n"); 54 Status = STATUS_INSUFFICIENT_RESOURCES; 55 goto cleanup; 56 } 57 58 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 59 Irp->IoStatus.Information = 0; 60 61 Stack = IoGetNextIrpStackLocation(Irp); 62 Stack->MajorFunction = IRP_MJ_PNP; 63 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE; 64 Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD; 65 Stack->Parameters.QueryInterface.Version = 1; 66 Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); 67 Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface; 68 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL; 69 70 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp); 71 if (Status == STATUS_PENDING) 72 { 73 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 74 Status = IoStatus.Status; 75 } 76 if (!NT_SUCCESS(Status)) 77 goto cleanup; 78 79 DeviceExtension->BusInterface = BusInterface; 80 BusInterface = NULL; 81 Status = STATUS_SUCCESS; 82 83 cleanup: 84 if (BusInterface) ExFreePool(BusInterface); 85 return Status; 86 } 87 88 static NTSTATUS 89 ReleaseBusInterface( 90 IN PFDO_DEVICE_EXTENSION DeviceExtension) 91 { 92 NTSTATUS Status = STATUS_UNSUCCESSFUL; 93 94 if (DeviceExtension->BusInterface) 95 { 96 (*DeviceExtension->BusInterface->InterfaceDereference)( 97 DeviceExtension->BusInterface->Context); 98 DeviceExtension->BusInterface = NULL; 99 Status = STATUS_SUCCESS; 100 } 101 102 return Status; 103 } 104 105 NTSTATUS NTAPI 106 PciIdeXAddDevice( 107 IN PDRIVER_OBJECT DriverObject, 108 IN PDEVICE_OBJECT Pdo) 109 { 110 PPCIIDEX_DRIVER_EXTENSION DriverExtension; 111 PFDO_DEVICE_EXTENSION DeviceExtension; 112 PDEVICE_OBJECT Fdo; 113 ULONG BytesRead; 114 PCI_COMMON_CONFIG PciConfig; 115 NTSTATUS Status; 116 117 DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo); 118 119 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 120 ASSERT(DriverExtension); 121 122 Status = IoCreateDevice( 123 DriverObject, 124 sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize, 125 NULL, 126 FILE_DEVICE_BUS_EXTENDER, 127 FILE_DEVICE_SECURE_OPEN, 128 TRUE, 129 &Fdo); 130 if (!NT_SUCCESS(Status)) 131 { 132 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); 133 return Status; 134 } 135 136 DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension; 137 RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION)); 138 139 DeviceExtension->Common.IsFDO = TRUE; 140 141 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); 142 if (!NT_SUCCESS(Status)) 143 { 144 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); 145 return Status; 146 } 147 148 Status = GetBusInterface(DeviceExtension); 149 if (!NT_SUCCESS(Status)) 150 { 151 DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status); 152 IoDetachDevice(DeviceExtension->LowerDevice); 153 return Status; 154 } 155 156 BytesRead = (*DeviceExtension->BusInterface->GetBusData)( 157 DeviceExtension->BusInterface->Context, 158 PCI_WHICHSPACE_CONFIG, 159 &PciConfig, 160 0, 161 PCI_COMMON_HDR_LENGTH); 162 if (BytesRead != PCI_COMMON_HDR_LENGTH) 163 { 164 DPRINT("BusInterface->GetBusData() failed()\n"); 165 ReleaseBusInterface(DeviceExtension); 166 IoDetachDevice(DeviceExtension->LowerDevice); 167 return STATUS_IO_DEVICE_ERROR; 168 } 169 170 DeviceExtension->VendorId = PciConfig.VendorID; 171 DeviceExtension->DeviceId = PciConfig.DeviceID; 172 173 Fdo->Flags &= ~DO_DEVICE_INITIALIZING; 174 175 return STATUS_SUCCESS; 176 } 177 178 static NTSTATUS NTAPI 179 PciIdeXUdmaModesSupported( 180 IN IDENTIFY_DATA IdentifyData, 181 OUT PULONG BestXferMode, 182 OUT PULONG CurrentXferMode) 183 { 184 ULONG Best = PIO_MODE0; 185 ULONG Current = PIO_MODE0; 186 187 DPRINT("PciIdeXUdmaModesSupported(%lu, %p %p)\n", 188 IdentifyData, BestXferMode, CurrentXferMode); 189 190 /* FIXME: if current mode is a PIO mode, how to get it? 191 * At the moment, PIO_MODE0 is always returned... 192 */ 193 194 if (IdentifyData.TranslationFieldsValid & 0x2) 195 { 196 /* PIO modes and some DMA modes are supported */ 197 if (IdentifyData.AdvancedPIOModes & 0x10) 198 Best = PIO_MODE4; 199 else if (IdentifyData.AdvancedPIOModes & 0x8) 200 Best = PIO_MODE3; 201 else if (IdentifyData.AdvancedPIOModes & 0x4) 202 Best = PIO_MODE2; 203 else if (IdentifyData.AdvancedPIOModes & 0x2) 204 Best = PIO_MODE1; 205 else if (IdentifyData.AdvancedPIOModes & 0x1) 206 Best = PIO_MODE0; 207 208 if (IdentifyData.SingleWordDMASupport & 0x4) 209 Best = SWDMA_MODE2; 210 else if (IdentifyData.SingleWordDMASupport & 0x2) 211 Best = SWDMA_MODE1; 212 else if (IdentifyData.SingleWordDMASupport & 0x1) 213 Best = SWDMA_MODE0; 214 215 if (IdentifyData.SingleWordDMAActive & 0x4) 216 Current = SWDMA_MODE2; 217 else if (IdentifyData.SingleWordDMAActive & 0x2) 218 Current = SWDMA_MODE1; 219 else if (IdentifyData.SingleWordDMAActive & 0x1) 220 Current = SWDMA_MODE0; 221 222 if (IdentifyData.MultiWordDMASupport & 0x4) 223 Best = MWDMA_MODE2; 224 else if (IdentifyData.MultiWordDMASupport & 0x2) 225 Best = MWDMA_MODE1; 226 else if (IdentifyData.MultiWordDMASupport & 0x1) 227 Best = MWDMA_MODE0; 228 229 if (IdentifyData.MultiWordDMAActive & 0x4) 230 Current = MWDMA_MODE2; 231 else if (IdentifyData.MultiWordDMAActive & 0x2) 232 Current = MWDMA_MODE1; 233 else if (IdentifyData.MultiWordDMAActive & 0x1) 234 Current = MWDMA_MODE0; 235 } 236 237 if (IdentifyData.TranslationFieldsValid & 0x4) 238 { 239 /* UDMA modes are supported */ 240 if (IdentifyData.UltraDMAActive & 0x10) 241 Current = UDMA_MODE4; 242 else if (IdentifyData.UltraDMAActive & 0x8) 243 Current = UDMA_MODE3; 244 else if (IdentifyData.UltraDMAActive & 0x4) 245 Current = UDMA_MODE2; 246 else if (IdentifyData.UltraDMAActive & 0x2) 247 Current = UDMA_MODE1; 248 else if (IdentifyData.UltraDMAActive & 0x1) 249 Current = UDMA_MODE0; 250 251 if (IdentifyData.UltraDMASupport & 0x10) 252 Best = UDMA_MODE4; 253 else if (IdentifyData.UltraDMASupport & 0x8) 254 Best = UDMA_MODE3; 255 else if (IdentifyData.UltraDMASupport & 0x4) 256 Best = UDMA_MODE2; 257 else if (IdentifyData.UltraDMASupport & 0x2) 258 Best = UDMA_MODE1; 259 else if (IdentifyData.UltraDMASupport & 0x1) 260 Best = UDMA_MODE0; 261 } 262 263 *BestXferMode = Best; 264 *CurrentXferMode = Current; 265 return TRUE; 266 } 267 268 static NTSTATUS 269 PciIdeXFdoStartDevice( 270 IN PDEVICE_OBJECT DeviceObject, 271 IN PIRP Irp) 272 { 273 PPCIIDEX_DRIVER_EXTENSION DriverExtension; 274 PFDO_DEVICE_EXTENSION DeviceExtension; 275 PCM_RESOURCE_LIST ResourceList; 276 NTSTATUS Status; 277 278 DPRINT("PciIdeXStartDevice(%p %p)\n", DeviceObject, Irp); 279 280 DriverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject); 281 ASSERT(DriverExtension); 282 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 283 ASSERT(DeviceExtension); 284 ASSERT(DeviceExtension->Common.IsFDO); 285 286 DeviceExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES); 287 DeviceExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize; 288 Status = DriverExtension->HwGetControllerProperties( 289 DeviceExtension->MiniControllerExtension, 290 &DeviceExtension->Properties); 291 if (!NT_SUCCESS(Status)) 292 return Status; 293 294 DriverExtension->HwUdmaModesSupported = DeviceExtension->Properties.PciIdeUdmaModesSupported; 295 if (!DriverExtension->HwUdmaModesSupported) 296 /* This method is optional, so provide our own one */ 297 DriverExtension->HwUdmaModesSupported = PciIdeXUdmaModesSupported; 298 299 /* Get bus master port base, if any */ 300 ResourceList = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources; 301 if (ResourceList 302 && ResourceList->Count == 1 303 && ResourceList->List[0].PartialResourceList.Count == 1 304 && ResourceList->List[0].PartialResourceList.Version == 1 305 && ResourceList->List[0].PartialResourceList.Revision == 1 306 && ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type == CmResourceTypePort 307 && ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length == 16) 308 { 309 DeviceExtension->BusMasterPortBase = ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start; 310 } 311 return STATUS_SUCCESS; 312 } 313 314 static NTSTATUS 315 PciIdeXFdoQueryBusRelations( 316 IN PDEVICE_OBJECT DeviceObject, 317 OUT PDEVICE_RELATIONS* pDeviceRelations) 318 { 319 PFDO_DEVICE_EXTENSION DeviceExtension; 320 PDEVICE_RELATIONS DeviceRelations = NULL; 321 PDEVICE_OBJECT Pdo; 322 PPDO_DEVICE_EXTENSION PdoDeviceExtension; 323 ULONG i, j; 324 ULONG PDOs = 0; 325 IDE_CHANNEL_STATE ChannelState; 326 NTSTATUS Status; 327 328 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 329 ASSERT(DeviceExtension); 330 ASSERT(DeviceExtension->Common.IsFDO); 331 332 for (i = 0; i < MAX_IDE_CHANNEL; i++) 333 { 334 if (DeviceExtension->Pdo[i]) 335 { 336 PDOs++; 337 continue; 338 } 339 ChannelState = DeviceExtension->Properties.PciIdeChannelEnabled( 340 DeviceExtension->MiniControllerExtension, i); 341 if (ChannelState == ChannelDisabled) 342 { 343 DPRINT("Channel %lu is disabled\n", i); 344 continue; 345 } 346 347 /* Need to create a PDO */ 348 Status = IoCreateDevice( 349 DeviceObject->DriverObject, 350 sizeof(PDO_DEVICE_EXTENSION), 351 NULL, 352 FILE_DEVICE_CONTROLLER, 353 FILE_AUTOGENERATED_DEVICE_NAME, 354 FALSE, 355 &Pdo); 356 if (!NT_SUCCESS(Status)) 357 /* FIXME: handle error */ 358 continue; 359 360 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension; 361 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 362 PdoDeviceExtension->Common.IsFDO = FALSE; 363 PdoDeviceExtension->Channel = i; 364 PdoDeviceExtension->ControllerFdo = DeviceObject; 365 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 366 Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 367 368 DeviceExtension->Pdo[i] = Pdo; 369 PDOs++; 370 } 371 372 if (PDOs == 0) 373 { 374 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool( 375 PagedPool, 376 sizeof(DEVICE_RELATIONS)); 377 } 378 else 379 { 380 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool( 381 PagedPool, 382 sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PDOs - 1)); 383 } 384 if (!DeviceRelations) 385 return STATUS_INSUFFICIENT_RESOURCES; 386 387 DeviceRelations->Count = PDOs; 388 for (i = 0, j = 0; i < MAX_IDE_CHANNEL; i++) 389 { 390 if (DeviceExtension->Pdo[i]) 391 { 392 ObReferenceObject(DeviceExtension->Pdo[i]); 393 DeviceRelations->Objects[j++] = DeviceExtension->Pdo[i]; 394 } 395 } 396 397 *pDeviceRelations = DeviceRelations; 398 return STATUS_SUCCESS; 399 } 400 401 NTSTATUS NTAPI 402 PciIdeXFdoPnpDispatch( 403 IN PDEVICE_OBJECT DeviceObject, 404 IN PIRP Irp) 405 { 406 ULONG MinorFunction; 407 PIO_STACK_LOCATION Stack; 408 ULONG_PTR Information = Irp->IoStatus.Information; 409 NTSTATUS Status; 410 411 Stack = IoGetCurrentIrpStackLocation(Irp); 412 MinorFunction = Stack->MinorFunction; 413 414 switch (MinorFunction) 415 { 416 case IRP_MN_START_DEVICE: /* 0x00 */ 417 { 418 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 419 /* Call lower driver */ 420 Status = ForwardIrpAndWait(DeviceObject, Irp); 421 if (NT_SUCCESS(Status)) 422 Status = PciIdeXFdoStartDevice(DeviceObject, Irp); 423 break; 424 } 425 case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */ 426 { 427 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n"); 428 Status = STATUS_UNSUCCESSFUL; 429 break; 430 } 431 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */ 432 { 433 switch (Stack->Parameters.QueryDeviceRelations.Type) 434 { 435 case BusRelations: 436 { 437 PDEVICE_RELATIONS DeviceRelations = NULL; 438 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 439 Status = PciIdeXFdoQueryBusRelations(DeviceObject, &DeviceRelations); 440 Information = (ULONG_PTR)DeviceRelations; 441 break; 442 } 443 default: 444 { 445 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 446 Stack->Parameters.QueryDeviceRelations.Type); 447 Status = STATUS_NOT_IMPLEMENTED; 448 break; 449 } 450 } 451 break; 452 } 453 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */ 454 { 455 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n"); 456 Information |= PNP_DEVICE_NOT_DISABLEABLE; 457 Status = STATUS_SUCCESS; 458 break; 459 } 460 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */ 461 { 462 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 463 return ForwardIrpAndForget(DeviceObject, Irp); 464 } 465 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */ 466 { 467 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n"); 468 return ForwardIrpAndForget(DeviceObject, Irp); 469 } 470 default: 471 { 472 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction); 473 return ForwardIrpAndForget(DeviceObject, Irp); 474 } 475 } 476 477 Irp->IoStatus.Information = Information; 478 Irp->IoStatus.Status = Status; 479 IoCompleteRequest(Irp, IO_NO_INCREMENT); 480 return Status; 481 } 482