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