1 /* 2 * PROJECT: ReactOS PCI bus driver 3 * FILE: fdo.c 4 * PURPOSE: PCI device object dispatch routines 5 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 6 * UPDATE HISTORY: 7 * 10-09-2001 CSH Created 8 */ 9 10 #include "pci.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 /*** PRIVATE *****************************************************************/ 16 17 static NTSTATUS 18 FdoLocateChildDevice( 19 PPCI_DEVICE *Device, 20 PFDO_DEVICE_EXTENSION DeviceExtension, 21 PCI_SLOT_NUMBER SlotNumber, 22 PPCI_COMMON_CONFIG PciConfig) 23 { 24 PLIST_ENTRY CurrentEntry; 25 PPCI_DEVICE CurrentDevice; 26 27 DPRINT("Called\n"); 28 29 CurrentEntry = DeviceExtension->DeviceListHead.Flink; 30 while (CurrentEntry != &DeviceExtension->DeviceListHead) 31 { 32 CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry); 33 34 /* If both vendor ID and device ID match, it is the same device */ 35 if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) && 36 (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID) && 37 (SlotNumber.u.AsULONG == CurrentDevice->SlotNumber.u.AsULONG)) 38 { 39 *Device = CurrentDevice; 40 DPRINT("Done\n"); 41 return STATUS_SUCCESS; 42 } 43 44 CurrentEntry = CurrentEntry->Flink; 45 } 46 47 *Device = NULL; 48 DPRINT("Done\n"); 49 return STATUS_UNSUCCESSFUL; 50 } 51 52 53 static NTSTATUS 54 FdoEnumerateDevices( 55 PDEVICE_OBJECT DeviceObject) 56 { 57 PFDO_DEVICE_EXTENSION DeviceExtension; 58 PCI_COMMON_CONFIG PciConfig; 59 PPCI_DEVICE Device; 60 PCI_SLOT_NUMBER SlotNumber; 61 ULONG DeviceNumber; 62 ULONG FunctionNumber; 63 ULONG Size; 64 NTSTATUS Status; 65 66 DPRINT("Called\n"); 67 68 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 69 70 DeviceExtension->DeviceListCount = 0; 71 72 /* Enumerate devices on the PCI bus */ 73 SlotNumber.u.AsULONG = 0; 74 for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) 75 { 76 SlotNumber.u.bits.DeviceNumber = DeviceNumber; 77 for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) 78 { 79 SlotNumber.u.bits.FunctionNumber = FunctionNumber; 80 81 DPRINT("Bus %1lu Device %2lu Func %1lu\n", 82 DeviceExtension->BusNumber, 83 DeviceNumber, 84 FunctionNumber); 85 86 RtlZeroMemory(&PciConfig, 87 sizeof(PCI_COMMON_CONFIG)); 88 89 Size = HalGetBusData(PCIConfiguration, 90 DeviceExtension->BusNumber, 91 SlotNumber.u.AsULONG, 92 &PciConfig, 93 PCI_COMMON_HDR_LENGTH); 94 DPRINT("Size %lu\n", Size); 95 if (Size < PCI_COMMON_HDR_LENGTH) 96 { 97 if (FunctionNumber == 0) 98 { 99 break; 100 } 101 else 102 { 103 continue; 104 } 105 } 106 107 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n", 108 DeviceExtension->BusNumber, 109 DeviceNumber, 110 FunctionNumber, 111 PciConfig.VendorID, 112 PciConfig.DeviceID); 113 114 if (PciConfig.VendorID == 0 && PciConfig.DeviceID == 0) 115 { 116 DPRINT("Filter out devices with null vendor and device ID\n"); 117 continue; 118 } 119 120 Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig); 121 if (!NT_SUCCESS(Status)) 122 { 123 Device = ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_DEVICE), TAG_PCI); 124 if (!Device) 125 { 126 /* FIXME: Cleanup resources for already discovered devices */ 127 return STATUS_INSUFFICIENT_RESOURCES; 128 } 129 130 RtlZeroMemory(Device, 131 sizeof(PCI_DEVICE)); 132 133 Device->BusNumber = DeviceExtension->BusNumber; 134 135 RtlCopyMemory(&Device->SlotNumber, 136 &SlotNumber, 137 sizeof(PCI_SLOT_NUMBER)); 138 139 RtlCopyMemory(&Device->PciConfig, 140 &PciConfig, 141 sizeof(PCI_COMMON_CONFIG)); 142 143 ExInterlockedInsertTailList( 144 &DeviceExtension->DeviceListHead, 145 &Device->ListEntry, 146 &DeviceExtension->DeviceListLock); 147 } 148 149 DeviceExtension->DeviceListCount++; 150 151 /* Skip to next device if the current one is not a multifunction device */ 152 if ((FunctionNumber == 0) && 153 ((PciConfig.HeaderType & 0x80) == 0)) 154 { 155 break; 156 } 157 } 158 } 159 160 DPRINT("Done\n"); 161 162 return STATUS_SUCCESS; 163 } 164 165 166 static NTSTATUS 167 FdoQueryBusRelations( 168 IN PDEVICE_OBJECT DeviceObject, 169 IN PIRP Irp, 170 PIO_STACK_LOCATION IrpSp) 171 { 172 PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL; 173 PFDO_DEVICE_EXTENSION DeviceExtension; 174 PDEVICE_RELATIONS Relations; 175 PLIST_ENTRY CurrentEntry; 176 PPCI_DEVICE Device; 177 NTSTATUS Status; 178 BOOLEAN ErrorOccurred; 179 NTSTATUS ErrorStatus; 180 ULONG Size; 181 ULONG i; 182 183 UNREFERENCED_PARAMETER(IrpSp); 184 185 DPRINT("Called\n"); 186 187 ErrorStatus = STATUS_INSUFFICIENT_RESOURCES; 188 189 Status = STATUS_SUCCESS; 190 191 ErrorOccurred = FALSE; 192 193 FdoEnumerateDevices(DeviceObject); 194 195 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 196 197 if (Irp->IoStatus.Information) 198 { 199 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS 200 structure so we must merge this structure with our own */ 201 DPRINT1("FIXME: leaking old bus relations\n"); 202 } 203 204 Size = sizeof(DEVICE_RELATIONS) + 205 sizeof(Relations->Objects) * (DeviceExtension->DeviceListCount - 1); 206 Relations = ExAllocatePoolWithTag(PagedPool, Size, TAG_PCI); 207 if (!Relations) 208 return STATUS_INSUFFICIENT_RESOURCES; 209 210 Relations->Count = DeviceExtension->DeviceListCount; 211 212 i = 0; 213 CurrentEntry = DeviceExtension->DeviceListHead.Flink; 214 while (CurrentEntry != &DeviceExtension->DeviceListHead) 215 { 216 Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry); 217 218 PdoDeviceExtension = NULL; 219 220 if (!Device->Pdo) 221 { 222 /* Create a physical device object for the 223 device as it does not already have one */ 224 Status = IoCreateDevice(DeviceObject->DriverObject, 225 sizeof(PDO_DEVICE_EXTENSION), 226 NULL, 227 FILE_DEVICE_CONTROLLER, 228 FILE_AUTOGENERATED_DEVICE_NAME, 229 FALSE, 230 &Device->Pdo); 231 if (!NT_SUCCESS(Status)) 232 { 233 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status); 234 ErrorStatus = Status; 235 ErrorOccurred = TRUE; 236 break; 237 } 238 239 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 240 241 //Device->Pdo->Flags |= DO_POWER_PAGABLE; 242 243 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension; 244 245 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 246 247 PdoDeviceExtension->Common.IsFDO = FALSE; 248 249 PdoDeviceExtension->Common.DeviceObject = Device->Pdo; 250 251 PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0; 252 253 PdoDeviceExtension->Fdo = DeviceObject; 254 255 PdoDeviceExtension->PciDevice = Device; 256 257 /* Add Device ID string */ 258 Status = PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID, Device); 259 if (!NT_SUCCESS(Status)) 260 { 261 ErrorStatus = Status; 262 ErrorOccurred = TRUE; 263 break; 264 } 265 266 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer); 267 268 /* Add Instance ID string */ 269 Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID, Device); 270 if (!NT_SUCCESS(Status)) 271 { 272 ErrorStatus = Status; 273 ErrorOccurred = TRUE; 274 break; 275 } 276 277 /* Add Hardware IDs string */ 278 Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs, Device); 279 if (!NT_SUCCESS(Status)) 280 { 281 ErrorStatus = Status; 282 ErrorOccurred = TRUE; 283 break; 284 } 285 286 /* Add Compatible IDs string */ 287 Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs, Device); 288 if (!NT_SUCCESS(Status)) 289 { 290 ErrorStatus = Status; 291 ErrorOccurred = TRUE; 292 break; 293 } 294 295 /* Add device description string */ 296 Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device); 297 if (!NT_SUCCESS(Status)) 298 { 299 ErrorStatus = Status; 300 ErrorOccurred = TRUE; 301 break; 302 } 303 304 /* Add device location string */ 305 Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device); 306 if (!NT_SUCCESS(Status)) 307 { 308 ErrorStatus = Status; 309 ErrorOccurred = TRUE; 310 break; 311 } 312 } 313 314 /* Reference the physical device object. The PnP manager 315 will dereference it again when it is no longer needed */ 316 ObReferenceObject(Device->Pdo); 317 318 Relations->Objects[i] = Device->Pdo; 319 320 i++; 321 322 CurrentEntry = CurrentEntry->Flink; 323 } 324 325 if (ErrorOccurred) 326 { 327 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */ 328 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */ 329 if (PdoDeviceExtension) 330 { 331 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID); 332 RtlFreeUnicodeString(&PdoDeviceExtension->InstanceID); 333 RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIDs); 334 RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIDs); 335 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription); 336 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceLocation); 337 } 338 339 ExFreePoolWithTag(Relations, TAG_PCI); 340 return ErrorStatus; 341 } 342 343 Irp->IoStatus.Information = (ULONG_PTR)Relations; 344 345 DPRINT("Done\n"); 346 347 return Status; 348 } 349 350 351 static NTSTATUS 352 FdoStartDevice( 353 IN PDEVICE_OBJECT DeviceObject, 354 IN PIRP Irp) 355 { 356 PFDO_DEVICE_EXTENSION DeviceExtension; 357 PCM_RESOURCE_LIST AllocatedResources; 358 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; 359 ULONG FoundBusNumber = FALSE; 360 ULONG i; 361 362 DPRINT("Called\n"); 363 364 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 365 366 AllocatedResources = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources; 367 if (!AllocatedResources) 368 { 369 DPRINT("No allocated resources sent to driver\n"); 370 return STATUS_INSUFFICIENT_RESOURCES; 371 } 372 373 if (AllocatedResources->Count < 1) 374 { 375 DPRINT("Not enough allocated resources sent to driver\n"); 376 return STATUS_INSUFFICIENT_RESOURCES; 377 } 378 379 if (AllocatedResources->List[0].PartialResourceList.Version != 1 || 380 AllocatedResources->List[0].PartialResourceList.Revision != 1) 381 return STATUS_REVISION_MISMATCH; 382 383 ASSERT(DeviceExtension->State == dsStopped); 384 385 /* By default, use the bus number in the resource list header */ 386 DeviceExtension->BusNumber = AllocatedResources->List[0].BusNumber; 387 388 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) 389 { 390 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; 391 switch (ResourceDescriptor->Type) 392 { 393 case CmResourceTypeBusNumber: 394 if (FoundBusNumber || ResourceDescriptor->u.BusNumber.Length < 1) 395 return STATUS_INVALID_PARAMETER; 396 397 /* Use this one instead */ 398 ASSERT(AllocatedResources->List[0].BusNumber == ResourceDescriptor->u.BusNumber.Start); 399 DeviceExtension->BusNumber = ResourceDescriptor->u.BusNumber.Start; 400 DPRINT("Found bus number resource: %lu\n", DeviceExtension->BusNumber); 401 FoundBusNumber = TRUE; 402 break; 403 404 default: 405 DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type); 406 } 407 } 408 409 InitializeListHead(&DeviceExtension->DeviceListHead); 410 KeInitializeSpinLock(&DeviceExtension->DeviceListLock); 411 DeviceExtension->DeviceListCount = 0; 412 DeviceExtension->State = dsStarted; 413 414 ExInterlockedInsertTailList( 415 &DriverExtension->BusListHead, 416 &DeviceExtension->ListEntry, 417 &DriverExtension->BusListLock); 418 419 Irp->IoStatus.Information = 0; 420 421 return STATUS_SUCCESS; 422 } 423 424 425 /*** PUBLIC ******************************************************************/ 426 427 NTSTATUS 428 FdoPnpControl( 429 PDEVICE_OBJECT DeviceObject, 430 PIRP Irp) 431 /* 432 * FUNCTION: Handle Plug and Play IRPs for the PCI device object 433 * ARGUMENTS: 434 * DeviceObject = Pointer to functional device object of the PCI driver 435 * Irp = Pointer to IRP that should be handled 436 * RETURNS: 437 * Status 438 */ 439 { 440 PFDO_DEVICE_EXTENSION DeviceExtension; 441 PIO_STACK_LOCATION IrpSp; 442 NTSTATUS Status = Irp->IoStatus.Status; 443 444 DPRINT("Called\n"); 445 446 DeviceExtension = DeviceObject->DeviceExtension; 447 448 IrpSp = IoGetCurrentIrpStackLocation(Irp); 449 switch (IrpSp->MinorFunction) 450 { 451 #if 0 452 case IRP_MN_CANCEL_REMOVE_DEVICE: 453 Status = STATUS_NOT_IMPLEMENTED; 454 break; 455 456 case IRP_MN_CANCEL_STOP_DEVICE: 457 Status = STATUS_NOT_IMPLEMENTED; 458 break; 459 460 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 461 Status = STATUS_NOT_IMPLEMENTED; 462 break; 463 464 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 465 Status = STATUS_NOT_IMPLEMENTED; 466 break; 467 #endif 468 case IRP_MN_QUERY_DEVICE_RELATIONS: 469 if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) 470 break; 471 472 Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp); 473 Irp->IoStatus.Status = Status; 474 IoCompleteRequest(Irp, IO_NO_INCREMENT); 475 return Status; 476 #if 0 477 case IRP_MN_QUERY_PNP_DEVICE_STATE: 478 Status = STATUS_NOT_IMPLEMENTED; 479 break; 480 481 case IRP_MN_QUERY_REMOVE_DEVICE: 482 Status = STATUS_NOT_IMPLEMENTED; 483 break; 484 #endif 485 case IRP_MN_START_DEVICE: 486 DPRINT("IRP_MN_START_DEVICE received\n"); 487 Status = STATUS_UNSUCCESSFUL; 488 489 if (IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp)) 490 { 491 Status = Irp->IoStatus.Status; 492 if (NT_SUCCESS(Status)) 493 { 494 Status = FdoStartDevice(DeviceObject, Irp); 495 } 496 } 497 498 Irp->IoStatus.Status = Status; 499 IoCompleteRequest(Irp, IO_NO_INCREMENT); 500 return Status; 501 502 case IRP_MN_QUERY_STOP_DEVICE: 503 /* We don't support stopping yet */ 504 Status = STATUS_UNSUCCESSFUL; 505 Irp->IoStatus.Status = Status; 506 IoCompleteRequest(Irp, IO_NO_INCREMENT); 507 return Status; 508 509 case IRP_MN_STOP_DEVICE: 510 /* We can't fail this one so we fail the QUERY_STOP request that precedes it */ 511 break; 512 #if 0 513 case IRP_MN_SURPRISE_REMOVAL: 514 Status = STATUS_NOT_IMPLEMENTED; 515 break; 516 #endif 517 518 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 519 break; 520 521 case IRP_MN_REMOVE_DEVICE: 522 /* Detach the device object from the device stack */ 523 IoDetachDevice(DeviceExtension->Ldo); 524 525 /* Delete the device object */ 526 IoDeleteDevice(DeviceObject); 527 528 /* Return success */ 529 Status = STATUS_SUCCESS; 530 break; 531 532 case IRP_MN_QUERY_CAPABILITIES: 533 case IRP_MN_QUERY_PNP_DEVICE_STATE: 534 /* Don't print the warning, too much noise */ 535 break; 536 537 default: 538 DPRINT1("Unknown PNP minor function 0x%x\n", IrpSp->MinorFunction); 539 break; 540 } 541 542 Irp->IoStatus.Status = Status; 543 IoSkipCurrentIrpStackLocation(Irp); 544 Status = IoCallDriver(DeviceExtension->Ldo, Irp); 545 546 DPRINT("Leaving. Status 0x%lx\n", Status); 547 548 return Status; 549 } 550 551 552 NTSTATUS 553 FdoPowerControl( 554 PDEVICE_OBJECT DeviceObject, 555 PIRP Irp) 556 /* 557 * FUNCTION: Handle power management IRPs for the PCI device object 558 * ARGUMENTS: 559 * DeviceObject = Pointer to functional device object of the PCI driver 560 * Irp = Pointer to IRP that should be handled 561 * RETURNS: 562 * Status 563 */ 564 { 565 PFDO_DEVICE_EXTENSION DeviceExtension; 566 NTSTATUS Status; 567 568 DPRINT("Called\n"); 569 570 DeviceExtension = DeviceObject->DeviceExtension; 571 572 PoStartNextPowerIrp(Irp); 573 IoSkipCurrentIrpStackLocation(Irp); 574 Status = PoCallDriver(DeviceExtension->Ldo, Irp); 575 576 DPRINT("Leaving. Status 0x%X\n", Status); 577 578 return Status; 579 } 580 581 /* EOF */ 582