1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: hal/halx86/legacy/bus/pcibus.c 5 * PURPOSE: PCI Bus Support (Configuration Space, Resource Allocation) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <hal.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) 16 #pragma alloc_text(INIT, HalpInitializePciStubs) 17 #pragma alloc_text(INIT, HalpQueryPciRegistryInfo) 18 #pragma alloc_text(INIT, HalpRegisterPciDebuggingDeviceInfo) 19 #pragma alloc_text(INIT, HalpReleasePciDeviceForDebugging) 20 #pragma alloc_text(INIT, HalpSetupPciDeviceForDebugging) 21 #endif 22 23 /* GLOBALS *******************************************************************/ 24 25 extern BOOLEAN HalpPciLockSettings; 26 ULONG HalpBusType; 27 28 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}}; 29 30 BOOLEAN HalpPCIConfigInitialized; 31 ULONG HalpMinPciBus, HalpMaxPciBus; 32 KSPIN_LOCK HalpPCIConfigLock; 33 PCI_CONFIG_HANDLER PCIConfigHandler; 34 35 /* PCI Operation Matrix */ 36 UCHAR PCIDeref[4][4] = 37 { 38 {0, 1, 2, 2}, // ULONG-aligned offset 39 {1, 1, 1, 1}, // UCHAR-aligned offset 40 {2, 1, 2, 2}, // USHORT-aligned offset 41 {1, 1, 1, 1} // UCHAR-aligned offset 42 }; 43 44 /* Type 1 PCI Bus */ 45 PCI_CONFIG_HANDLER PCIConfigHandlerType1 = 46 { 47 /* Synchronization */ 48 (FncSync)HalpPCISynchronizeType1, 49 (FncReleaseSync)HalpPCIReleaseSynchronzationType1, 50 51 /* Read */ 52 { 53 (FncConfigIO)HalpPCIReadUlongType1, 54 (FncConfigIO)HalpPCIReadUcharType1, 55 (FncConfigIO)HalpPCIReadUshortType1 56 }, 57 58 /* Write */ 59 { 60 (FncConfigIO)HalpPCIWriteUlongType1, 61 (FncConfigIO)HalpPCIWriteUcharType1, 62 (FncConfigIO)HalpPCIWriteUshortType1 63 } 64 }; 65 66 /* Type 2 PCI Bus */ 67 PCI_CONFIG_HANDLER PCIConfigHandlerType2 = 68 { 69 /* Synchronization */ 70 (FncSync)HalpPCISynchronizeType2, 71 (FncReleaseSync)HalpPCIReleaseSynchronizationType2, 72 73 /* Read */ 74 { 75 (FncConfigIO)HalpPCIReadUlongType2, 76 (FncConfigIO)HalpPCIReadUcharType2, 77 (FncConfigIO)HalpPCIReadUshortType2 78 }, 79 80 /* Write */ 81 { 82 (FncConfigIO)HalpPCIWriteUlongType2, 83 (FncConfigIO)HalpPCIWriteUcharType2, 84 (FncConfigIO)HalpPCIWriteUshortType2 85 } 86 }; 87 88 PCIPBUSDATA HalpFakePciBusData = 89 { 90 { 91 PCI_DATA_TAG, 92 PCI_DATA_VERSION, 93 HalpReadPCIConfig, 94 HalpWritePCIConfig, 95 NULL, 96 NULL, 97 {{{0, 0, 0}}}, 98 {0, 0, 0, 0} 99 }, 100 {{0, 0}}, 101 32, 102 }; 103 104 BUS_HANDLER HalpFakePciBusHandler = 105 { 106 1, 107 PCIBus, 108 PCIConfiguration, 109 0, 110 NULL, 111 NULL, 112 &HalpFakePciBusData, 113 0, 114 NULL, 115 {0, 0, 0, 0}, 116 (PGETSETBUSDATA)HalpGetPCIData, 117 (PGETSETBUSDATA)HalpSetPCIData, 118 NULL, 119 HalpAssignPCISlotResources, 120 NULL, 121 NULL 122 }; 123 124 /* TYPE 1 FUNCTIONS **********************************************************/ 125 126 VOID 127 NTAPI 128 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler, 129 IN PCI_SLOT_NUMBER Slot, 130 IN PKIRQL Irql, 131 IN PPCI_TYPE1_CFG_BITS PciCfg1) 132 { 133 /* Setup the PCI Configuration Register */ 134 PciCfg1->u.AsULONG = 0; 135 PciCfg1->u.bits.BusNumber = BusHandler->BusNumber; 136 PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; 137 PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; 138 PciCfg1->u.bits.Enable = TRUE; 139 140 /* Acquire the lock */ 141 KeRaiseIrql(HIGH_LEVEL, Irql); 142 KiAcquireSpinLock(&HalpPCIConfigLock); 143 } 144 145 VOID 146 NTAPI 147 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler, 148 IN KIRQL Irql) 149 { 150 PCI_TYPE1_CFG_BITS PciCfg1; 151 152 /* Clear the PCI Configuration Register */ 153 PciCfg1.u.AsULONG = 0; 154 WRITE_PORT_ULONG(((PPCIPBUSDATA)BusHandler->BusData)->Config.Type1.Address, 155 PciCfg1.u.AsULONG); 156 157 /* Release the lock */ 158 KiReleaseSpinLock(&HalpPCIConfigLock); 159 KeLowerIrql(Irql); 160 } 161 162 TYPE1_READ(HalpPCIReadUcharType1, UCHAR) 163 TYPE1_READ(HalpPCIReadUshortType1, USHORT) 164 TYPE1_READ(HalpPCIReadUlongType1, ULONG) 165 TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR) 166 TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT) 167 TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG) 168 169 /* TYPE 2 FUNCTIONS **********************************************************/ 170 171 VOID 172 NTAPI 173 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler, 174 IN PCI_SLOT_NUMBER Slot, 175 IN PKIRQL Irql, 176 IN PPCI_TYPE2_ADDRESS_BITS PciCfg) 177 { 178 PCI_TYPE2_CSE_BITS PciCfg2Cse; 179 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 180 181 /* Setup the configuration register */ 182 PciCfg->u.AsUSHORT = 0; 183 PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber; 184 PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base; 185 186 /* Acquire the lock */ 187 KeRaiseIrql(HIGH_LEVEL, Irql); 188 KiAcquireSpinLock(&HalpPCIConfigLock); 189 190 /* Setup the CSE Register */ 191 PciCfg2Cse.u.AsUCHAR = 0; 192 PciCfg2Cse.u.bits.Enable = TRUE; 193 PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber; 194 PciCfg2Cse.u.bits.Key = -1; 195 196 /* Write the bus number and CSE */ 197 WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 198 (UCHAR)BusHandler->BusNumber); 199 WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); 200 } 201 202 VOID 203 NTAPI 204 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler, 205 IN KIRQL Irql) 206 { 207 PCI_TYPE2_CSE_BITS PciCfg2Cse; 208 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 209 210 /* Clear CSE and bus number */ 211 PciCfg2Cse.u.AsUCHAR = 0; 212 WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); 213 WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0); 214 215 /* Release the lock */ 216 KiReleaseSpinLock(&HalpPCIConfigLock); 217 KeLowerIrql(Irql); 218 } 219 220 TYPE2_READ(HalpPCIReadUcharType2, UCHAR) 221 TYPE2_READ(HalpPCIReadUshortType2, USHORT) 222 TYPE2_READ(HalpPCIReadUlongType2, ULONG) 223 TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR) 224 TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT) 225 TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG) 226 227 /* PCI CONFIGURATION SPACE ***************************************************/ 228 229 VOID 230 NTAPI 231 HalpPCIConfig(IN PBUS_HANDLER BusHandler, 232 IN PCI_SLOT_NUMBER Slot, 233 IN PUCHAR Buffer, 234 IN ULONG Offset, 235 IN ULONG Length, 236 IN FncConfigIO *ConfigIO) 237 { 238 KIRQL OldIrql; 239 ULONG i; 240 UCHAR State[20]; 241 242 /* Synchronize the operation */ 243 PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State); 244 245 /* Loop every increment */ 246 while (Length) 247 { 248 /* Find out the type of read/write we need to do */ 249 i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; 250 251 /* Do the read/write and return the number of bytes */ 252 i = ConfigIO[i]((PPCIPBUSDATA)BusHandler->BusData, 253 State, 254 Buffer, 255 Offset); 256 257 /* Increment the buffer position and offset, and decrease the length */ 258 Offset += i; 259 Buffer += i; 260 Length -= i; 261 } 262 263 /* Release the lock and PCI bus */ 264 PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql); 265 } 266 267 VOID 268 NTAPI 269 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler, 270 IN PCI_SLOT_NUMBER Slot, 271 IN PVOID Buffer, 272 IN ULONG Offset, 273 IN ULONG Length) 274 { 275 /* Validate the PCI Slot */ 276 if (!HalpValidPCISlot(BusHandler, Slot)) 277 { 278 /* Fill the buffer with invalid data */ 279 RtlFillMemory(Buffer, Length, -1); 280 } 281 else 282 { 283 /* Send the request */ 284 HalpPCIConfig(BusHandler, 285 Slot, 286 Buffer, 287 Offset, 288 Length, 289 PCIConfigHandler.ConfigRead); 290 } 291 } 292 293 VOID 294 NTAPI 295 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler, 296 IN PCI_SLOT_NUMBER Slot, 297 IN PVOID Buffer, 298 IN ULONG Offset, 299 IN ULONG Length) 300 { 301 /* Validate the PCI Slot */ 302 if (HalpValidPCISlot(BusHandler, Slot)) 303 { 304 /* Send the request */ 305 HalpPCIConfig(BusHandler, 306 Slot, 307 Buffer, 308 Offset, 309 Length, 310 PCIConfigHandler.ConfigWrite); 311 } 312 } 313 314 BOOLEAN 315 NTAPI 316 HalpValidPCISlot(IN PBUS_HANDLER BusHandler, 317 IN PCI_SLOT_NUMBER Slot) 318 { 319 PCI_SLOT_NUMBER MultiSlot; 320 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 321 UCHAR HeaderType; 322 //ULONG Device; 323 324 /* Simple validation */ 325 if (Slot.u.bits.Reserved) return FALSE; 326 if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE; 327 328 /* Function 0 doesn't need checking */ 329 if (!Slot.u.bits.FunctionNumber) return TRUE; 330 331 /* Functions 0+ need Multi-Function support, so check the slot */ 332 //Device = Slot.u.bits.DeviceNumber; 333 MultiSlot = Slot; 334 MultiSlot.u.bits.FunctionNumber = 0; 335 336 /* Send function 0 request to get the header back */ 337 HalpReadPCIConfig(BusHandler, 338 MultiSlot, 339 &HeaderType, 340 FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType), 341 sizeof(UCHAR)); 342 343 /* Now make sure the header is multi-function */ 344 if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE; 345 return TRUE; 346 } 347 348 /* HAL PCI CALLBACKS *********************************************************/ 349 350 ULONG 351 NTAPI 352 HalpGetPCIData(IN PBUS_HANDLER BusHandler, 353 IN PBUS_HANDLER RootHandler, 354 IN ULONG SlotNumber, 355 IN PVOID Buffer, 356 IN ULONG Offset, 357 IN ULONG Length) 358 { 359 PCI_SLOT_NUMBER Slot; 360 UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; 361 PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; 362 ULONG Len = 0; 363 364 Slot.u.AsULONG = SlotNumber; 365 #ifdef SARCH_XBOX 366 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely 367 * hang the Xbox. Also, the device number doesn't seem to be decoded for the 368 * video card, so it appears to be present on 1:0:0 - 1:31:0. 369 * We hack around these problems by indicating "device not present" for devices 370 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */ 371 if ((0 == BusHandler->BusNumber && 0 == Slot.u.bits.DeviceNumber && 372 (1 == Slot.u.bits.FunctionNumber || 2 == Slot.u.bits.FunctionNumber)) || 373 (1 == BusHandler->BusNumber && 0 != Slot.u.bits.DeviceNumber)) 374 { 375 DPRINT("Blacklisted PCI slot\n"); 376 if (0 == Offset && sizeof(USHORT) <= Length) 377 { 378 *(PUSHORT)Buffer = PCI_INVALID_VENDORID; 379 return sizeof(USHORT); 380 } 381 return 0; 382 } 383 #endif 384 385 /* Normalize the length */ 386 if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG); 387 388 /* Check if this is a vendor-specific read */ 389 if (Offset >= PCI_COMMON_HDR_LENGTH) 390 { 391 /* Read the header */ 392 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); 393 394 /* Make sure the vendor is valid */ 395 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 396 } 397 else 398 { 399 /* Read the entire header */ 400 Len = PCI_COMMON_HDR_LENGTH; 401 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); 402 403 /* Validate the vendor ID */ 404 if (PciConfig->VendorID == PCI_INVALID_VENDORID) 405 { 406 /* It's invalid, but we want to return this much */ 407 Len = sizeof(USHORT); 408 } 409 410 /* Now check if there's space left */ 411 if (Len < Offset) return 0; 412 413 /* There is, so return what's after the offset and normalize */ 414 Len -= Offset; 415 if (Len > Length) Len = Length; 416 417 /* Copy the data into the caller's buffer */ 418 RtlMoveMemory(Buffer, PciBuffer + Offset, Len); 419 420 /* Update buffer and offset, decrement total length */ 421 Offset += Len; 422 Buffer = (PVOID)((ULONG_PTR)Buffer + Len); 423 Length -= Len; 424 } 425 426 /* Now we still have something to copy */ 427 if (Length) 428 { 429 /* Check if it's vendor-specific data */ 430 if (Offset >= PCI_COMMON_HDR_LENGTH) 431 { 432 /* Read it now */ 433 HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length); 434 Len += Length; 435 } 436 } 437 438 /* Update the total length read */ 439 return Len; 440 } 441 442 ULONG 443 NTAPI 444 HalpSetPCIData(IN PBUS_HANDLER BusHandler, 445 IN PBUS_HANDLER RootHandler, 446 IN ULONG SlotNumber, 447 IN PVOID Buffer, 448 IN ULONG Offset, 449 IN ULONG Length) 450 { 451 PCI_SLOT_NUMBER Slot; 452 UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; 453 PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; 454 ULONG Len = 0; 455 456 Slot.u.AsULONG = SlotNumber; 457 #ifdef SARCH_XBOX 458 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely 459 * hang the Xbox. Also, the device number doesn't seem to be decoded for the 460 * video card, so it appears to be present on 1:0:0 - 1:31:0. 461 * We hack around these problems by indicating "device not present" for devices 462 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */ 463 if ((0 == BusHandler->BusNumber && 0 == Slot.u.bits.DeviceNumber && 464 (1 == Slot.u.bits.FunctionNumber || 2 == Slot.u.bits.FunctionNumber)) || 465 (1 == BusHandler->BusNumber && 0 != Slot.u.bits.DeviceNumber)) 466 { 467 DPRINT1("Trying to set data on blacklisted PCI slot\n"); 468 return 0; 469 } 470 #endif 471 472 /* Normalize the length */ 473 if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG); 474 475 /* Check if this is a vendor-specific read */ 476 if (Offset >= PCI_COMMON_HDR_LENGTH) 477 { 478 /* Read the header */ 479 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); 480 481 /* Make sure the vendor is valid */ 482 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 483 } 484 else 485 { 486 /* Read the entire header and validate the vendor ID */ 487 Len = PCI_COMMON_HDR_LENGTH; 488 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); 489 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 490 491 /* Return what's after the offset and normalize */ 492 Len -= Offset; 493 if (Len > Length) Len = Length; 494 495 /* Copy the specific caller data */ 496 RtlMoveMemory(PciBuffer + Offset, Buffer, Len); 497 498 /* Write the actual configuration data */ 499 HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len); 500 501 /* Update buffer and offset, decrement total length */ 502 Offset += Len; 503 Buffer = (PVOID)((ULONG_PTR)Buffer + Len); 504 Length -= Len; 505 } 506 507 /* Now we still have something to copy */ 508 if (Length) 509 { 510 /* Check if it's vendor-specific data */ 511 if (Offset >= PCI_COMMON_HDR_LENGTH) 512 { 513 /* Read it now */ 514 HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length); 515 Len += Length; 516 } 517 } 518 519 /* Update the total length read */ 520 return Len; 521 } 522 523 ULONG 524 NTAPI 525 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler, 526 IN PBUS_HANDLER RootHandler, 527 IN ULONG BusInterruptLevel, 528 IN ULONG BusInterruptVector, 529 OUT PKIRQL Irql, 530 OUT PKAFFINITY Affinity) 531 { 532 /* Validate the level first */ 533 if (BusInterruptLevel < 1) return 0; 534 535 /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */ 536 return HalGetInterruptVector(Isa, 537 0, 538 BusInterruptLevel, 539 0, 540 Irql, 541 Affinity); 542 } 543 544 VOID 545 NTAPI 546 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler, 547 IN PBUS_HANDLER RootHandler, 548 IN PCI_SLOT_NUMBER SlotNumber, 549 IN PPCI_COMMON_CONFIG PciData) 550 { 551 UNIMPLEMENTED_DBGBREAK(); 552 } 553 554 VOID 555 NTAPI 556 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler, 557 IN PBUS_HANDLER RootHandler, 558 IN PCI_SLOT_NUMBER SlotNumber, 559 IN PPCI_COMMON_CONFIG PciNewData, 560 IN PPCI_COMMON_CONFIG PciOldData) 561 { 562 UNIMPLEMENTED_DBGBREAK(); 563 } 564 565 NTSTATUS 566 NTAPI 567 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler, 568 IN PBUS_HANDLER RootHandler, 569 IN PCI_SLOT_NUMBER PciSlot, 570 OUT PSUPPORTED_RANGE *Range) 571 { 572 PCI_COMMON_HEADER PciData; 573 574 /* Read PCI configuration data */ 575 HalGetBusData(PCIConfiguration, 576 BusHandler->BusNumber, 577 PciSlot.u.AsULONG, 578 &PciData, 579 PCI_COMMON_HDR_LENGTH); 580 581 /* Make sure it's a real device */ 582 if (PciData.VendorID == PCI_INVALID_VENDORID) return STATUS_UNSUCCESSFUL; 583 584 /* Allocate the supported range structure */ 585 *Range = ExAllocatePoolWithTag(PagedPool, sizeof(SUPPORTED_RANGE), TAG_HAL); 586 if (!*Range) return STATUS_INSUFFICIENT_RESOURCES; 587 588 /* Set it up */ 589 RtlZeroMemory(*Range, sizeof(SUPPORTED_RANGE)); 590 (*Range)->Base = 1; 591 592 /* If the PCI device has no IRQ, nothing to do */ 593 if (!PciData.u.type0.InterruptPin) return STATUS_SUCCESS; 594 595 /* FIXME: The PCI IRQ Routing Miniport should be called */ 596 597 /* Also if the INT# seems bogus, nothing to do either */ 598 if ((PciData.u.type0.InterruptLine == 0) || 599 (PciData.u.type0.InterruptLine == 255)) 600 { 601 /* Fake success */ 602 return STATUS_SUCCESS; 603 } 604 605 /* Otherwise, the INT# should be valid, return it to the caller */ 606 (*Range)->Base = PciData.u.type0.InterruptLine; 607 (*Range)->Limit = PciData.u.type0.InterruptLine; 608 return STATUS_SUCCESS; 609 } 610 611 INIT_FUNCTION 612 NTSTATUS 613 NTAPI 614 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock, 615 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) 616 { 617 DPRINT1("Unimplemented!\n"); 618 return STATUS_NOT_IMPLEMENTED; 619 } 620 621 INIT_FUNCTION 622 NTSTATUS 623 NTAPI 624 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) 625 { 626 DPRINT1("Unimplemented!\n"); 627 return STATUS_NOT_IMPLEMENTED; 628 } 629 630 INIT_FUNCTION 631 VOID 632 NTAPI 633 HalpRegisterPciDebuggingDeviceInfo(VOID) 634 { 635 BOOLEAN Found = FALSE; 636 ULONG i; 637 PAGED_CODE(); 638 639 /* Loop PCI debugging devices */ 640 for (i = 0; i < 2; i++) 641 { 642 /* Reserved bit is set if we found one */ 643 if (HalpPciDebuggingDevice[i].u.bits.Reserved1) 644 { 645 Found = TRUE; 646 break; 647 } 648 } 649 650 /* Bail out if there aren't any */ 651 if (!Found) return; 652 653 /* FIXME: TODO */ 654 UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger" 655 "devices, but you have forgotten to implement this routine\n"); 656 } 657 658 static ULONG NTAPI 659 PciSize(ULONG Base, ULONG Mask) 660 { 661 ULONG Size = Mask & Base; /* Find the significant bits */ 662 Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */ 663 return Size; 664 } 665 666 NTSTATUS 667 NTAPI 668 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler, 669 IN PBUS_HANDLER RootHandler, 670 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList) 671 { 672 PPCIPBUSDATA BusData; 673 PCI_SLOT_NUMBER SlotNumber; 674 PSUPPORTED_RANGE Interrupt; 675 NTSTATUS Status; 676 677 /* Get PCI bus data */ 678 BusData = BusHandler->BusData; 679 SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber; 680 681 /* Get the IRQ supported range */ 682 Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt); 683 if (!NT_SUCCESS(Status)) return Status; 684 #ifndef _MINIHAL_ 685 /* Handle the /PCILOCK feature */ 686 if (HalpPciLockSettings) 687 { 688 /* /PCILOCK is not yet supported */ 689 UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported."); 690 } 691 #endif 692 /* Now create the correct resource list based on the supported bus ranges */ 693 #if 0 694 Status = HaliAdjustResourceListRange(BusHandler->BusAddresses, 695 Interrupt, 696 pResourceList); 697 #else 698 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n"); 699 Status = STATUS_SUCCESS; 700 #endif 701 702 /* Return to caller */ 703 ExFreePool(Interrupt); 704 return Status; 705 } 706 707 NTSTATUS 708 NTAPI 709 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler, 710 IN PBUS_HANDLER RootHandler, 711 IN PUNICODE_STRING RegistryPath, 712 IN PUNICODE_STRING DriverClassName OPTIONAL, 713 IN PDRIVER_OBJECT DriverObject, 714 IN PDEVICE_OBJECT DeviceObject OPTIONAL, 715 IN ULONG Slot, 716 IN OUT PCM_RESOURCE_LIST *AllocatedResources) 717 { 718 PCI_COMMON_CONFIG PciConfig; 719 SIZE_T Address; 720 ULONG ResourceCount; 721 ULONG Size[PCI_TYPE0_ADDRESSES]; 722 NTSTATUS Status = STATUS_SUCCESS; 723 UCHAR Offset; 724 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 725 PCI_SLOT_NUMBER SlotNumber; 726 ULONG WriteBuffer; 727 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n"); 728 729 /* FIXME: Should handle 64-bit addresses */ 730 731 /* Read configuration data */ 732 SlotNumber.u.AsULONG = Slot; 733 HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH); 734 735 /* Check if we read it correctly */ 736 if (PciConfig.VendorID == PCI_INVALID_VENDORID) 737 return STATUS_NO_SUCH_DEVICE; 738 739 /* Read the PCI configuration space for the device and store base address and 740 size information in temporary storage. Count the number of valid base addresses */ 741 ResourceCount = 0; 742 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) 743 { 744 if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address]) 745 PciConfig.u.type0.BaseAddresses[Address] = 0; 746 747 /* Memory resource */ 748 if (0 != PciConfig.u.type0.BaseAddresses[Address]) 749 { 750 ResourceCount++; 751 752 Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]); 753 754 /* Write 0xFFFFFFFF there */ 755 WriteBuffer = 0xffffffff; 756 HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG)); 757 758 /* Read that figure back from the config space */ 759 HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG)); 760 761 /* Write back initial value */ 762 HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG)); 763 } 764 } 765 766 /* Interrupt resource */ 767 if (0 != PciConfig.u.type0.InterruptPin && 768 0 != PciConfig.u.type0.InterruptLine && 769 0xFF != PciConfig.u.type0.InterruptLine) 770 ResourceCount++; 771 772 /* Allocate output buffer and initialize */ 773 *AllocatedResources = ExAllocatePoolWithTag( 774 PagedPool, 775 sizeof(CM_RESOURCE_LIST) + 776 (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), 777 TAG_HAL); 778 779 if (NULL == *AllocatedResources) 780 return STATUS_NO_MEMORY; 781 782 (*AllocatedResources)->Count = 1; 783 (*AllocatedResources)->List[0].InterfaceType = PCIBus; 784 (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber; 785 (*AllocatedResources)->List[0].PartialResourceList.Version = 1; 786 (*AllocatedResources)->List[0].PartialResourceList.Revision = 1; 787 (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount; 788 Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors; 789 790 /* Store configuration information */ 791 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) 792 { 793 if (0 != PciConfig.u.type0.BaseAddresses[Address]) 794 { 795 if (PCI_ADDRESS_MEMORY_SPACE == 796 (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) 797 { 798 Descriptor->Type = CmResourceTypeMemory; 799 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ 800 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */ 801 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK); 802 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK); 803 } 804 else if (PCI_ADDRESS_IO_SPACE == 805 (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) 806 { 807 Descriptor->Type = CmResourceTypePort; 808 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ 809 Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */ 810 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK; 811 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff); 812 } 813 else 814 { 815 ASSERT(FALSE); 816 return STATUS_UNSUCCESSFUL; 817 } 818 Descriptor++; 819 } 820 } 821 822 if (0 != PciConfig.u.type0.InterruptPin && 823 0 != PciConfig.u.type0.InterruptLine && 824 0xFF != PciConfig.u.type0.InterruptLine) 825 { 826 Descriptor->Type = CmResourceTypeInterrupt; 827 Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */ 828 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */ 829 Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine; 830 Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine; 831 Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; 832 833 Descriptor++; 834 } 835 836 ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount); 837 838 /* FIXME: Should store the resources in the registry resource map */ 839 840 return Status; 841 } 842 843 ULONG 844 NTAPI 845 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler, 846 IN ULONG BusNumber, 847 IN PCI_SLOT_NUMBER SlotNumber, 848 IN PVOID Buffer, 849 IN ULONG Offset, 850 IN ULONG Length) 851 { 852 BUS_HANDLER BusHandler; 853 854 /* Setup fake PCI Bus handler */ 855 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); 856 BusHandler.BusNumber = BusNumber; 857 858 /* Read configuration data */ 859 HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length); 860 861 /* Return length */ 862 return Length; 863 } 864 865 INIT_FUNCTION 866 PPCI_REGISTRY_INFO_INTERNAL 867 NTAPI 868 HalpQueryPciRegistryInfo(VOID) 869 { 870 #ifndef _MINIHAL_ 871 WCHAR NameBuffer[8]; 872 OBJECT_ATTRIBUTES ObjectAttributes; 873 UNICODE_STRING KeyName, ConfigName, IdentName; 874 HANDLE KeyHandle, BusKeyHandle, CardListHandle; 875 NTSTATUS Status; 876 UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100]; 877 PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer; 878 UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 879 sizeof(PCI_CARD_DESCRIPTOR)]; 880 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer; 881 KEY_FULL_INFORMATION KeyInformation; 882 ULONG ResultLength; 883 PWSTR Tag; 884 ULONG i, ElementCount; 885 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 886 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 887 PPCI_REGISTRY_INFO PciRegInfo; 888 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; 889 PPCI_CARD_DESCRIPTOR CardDescriptor; 890 891 /* Setup the object attributes for the key */ 892 RtlInitUnicodeString(&KeyName, 893 L"\\Registry\\Machine\\Hardware\\Description\\" 894 L"System\\MultiFunctionAdapter"); 895 InitializeObjectAttributes(&ObjectAttributes, 896 &KeyName, 897 OBJ_CASE_INSENSITIVE, 898 NULL, 899 NULL); 900 901 /* Open the key */ 902 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 903 if (!NT_SUCCESS(Status)) return NULL; 904 905 /* Setup the receiving string */ 906 KeyName.Buffer = NameBuffer; 907 KeyName.MaximumLength = sizeof(NameBuffer); 908 909 /* Setup the configuration and identifier key names */ 910 RtlInitUnicodeString(&ConfigName, L"Configuration Data"); 911 RtlInitUnicodeString(&IdentName, L"Identifier"); 912 913 /* Keep looping for each ID */ 914 for (i = 0; TRUE; i++) 915 { 916 /* Setup the key name */ 917 RtlIntegerToUnicodeString(i, 10, &KeyName); 918 InitializeObjectAttributes(&ObjectAttributes, 919 &KeyName, 920 OBJ_CASE_INSENSITIVE, 921 KeyHandle, 922 NULL); 923 924 /* Open it */ 925 Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes); 926 if (!NT_SUCCESS(Status)) 927 { 928 /* None left, fail */ 929 ZwClose(KeyHandle); 930 return NULL; 931 } 932 933 /* Read the registry data */ 934 Status = ZwQueryValueKey(BusKeyHandle, 935 &IdentName, 936 KeyValueFullInformation, 937 ValueInfo, 938 sizeof(KeyBuffer), 939 &ResultLength); 940 if (!NT_SUCCESS(Status)) 941 { 942 /* Failed, try the next one */ 943 ZwClose(BusKeyHandle); 944 continue; 945 } 946 947 /* Get the PCI Tag and validate it */ 948 Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); 949 if ((Tag[0] != L'P') || 950 (Tag[1] != L'C') || 951 (Tag[2] != L'I') || 952 (Tag[3])) 953 { 954 /* Not a valid PCI entry, skip it */ 955 ZwClose(BusKeyHandle); 956 continue; 957 } 958 959 /* Now read our PCI structure */ 960 Status = ZwQueryValueKey(BusKeyHandle, 961 &ConfigName, 962 KeyValueFullInformation, 963 ValueInfo, 964 sizeof(KeyBuffer), 965 &ResultLength); 966 ZwClose(BusKeyHandle); 967 if (!NT_SUCCESS(Status)) continue; 968 969 /* We read it OK! Get the actual resource descriptors */ 970 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) 971 ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); 972 PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) 973 ((ULONG_PTR)FullDescriptor-> 974 PartialResourceList.PartialDescriptors); 975 976 /* Check if this is our PCI Registry Information */ 977 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 978 { 979 /* It is, stop searching */ 980 break; 981 } 982 } 983 984 /* Close the key */ 985 ZwClose(KeyHandle); 986 987 /* Save the PCI information for later */ 988 PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1); 989 990 /* Assume no Card List entries */ 991 ElementCount = 0; 992 993 /* Set up for checking the PCI Card List key */ 994 RtlInitUnicodeString(&KeyName, 995 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 996 L"Control\\PnP\\PCI\\CardList"); 997 InitializeObjectAttributes(&ObjectAttributes, 998 &KeyName, 999 OBJ_CASE_INSENSITIVE, 1000 NULL, 1001 NULL); 1002 1003 /* Attempt to open it */ 1004 Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes); 1005 if (NT_SUCCESS(Status)) 1006 { 1007 /* It exists, so let's query it */ 1008 Status = ZwQueryKey(CardListHandle, 1009 KeyFullInformation, 1010 &KeyInformation, 1011 sizeof(KEY_FULL_INFORMATION), 1012 &ResultLength); 1013 if (!NT_SUCCESS(Status)) 1014 { 1015 /* Failed to query, so no info */ 1016 PciRegistryInfo = NULL; 1017 } 1018 else 1019 { 1020 /* Allocate the full structure */ 1021 PciRegistryInfo = 1022 ExAllocatePoolWithTag(NonPagedPool, 1023 sizeof(PCI_REGISTRY_INFO_INTERNAL) + 1024 (KeyInformation.Values * 1025 sizeof(PCI_CARD_DESCRIPTOR)), 1026 TAG_HAL); 1027 if (PciRegistryInfo) 1028 { 1029 /* Get the first card descriptor entry */ 1030 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1); 1031 1032 /* Loop all the values */ 1033 for (i = 0; i < KeyInformation.Values; i++) 1034 { 1035 /* Attempt to get the value */ 1036 Status = ZwEnumerateValueKey(CardListHandle, 1037 i, 1038 KeyValuePartialInformation, 1039 PartialValueInfo, 1040 sizeof(PartialKeyBuffer), 1041 &ResultLength); 1042 if (!NT_SUCCESS(Status)) 1043 { 1044 /* Something went wrong, stop the search */ 1045 break; 1046 } 1047 1048 /* Make sure it is correctly sized */ 1049 if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR)) 1050 { 1051 /* Sure is, copy it over */ 1052 *CardDescriptor = *(PPCI_CARD_DESCRIPTOR) 1053 PartialValueInfo->Data; 1054 1055 /* One more Card List entry */ 1056 ElementCount++; 1057 1058 /* Move to the next descriptor */ 1059 CardDescriptor = (CardDescriptor + 1); 1060 } 1061 } 1062 } 1063 } 1064 1065 /* Close the Card List key */ 1066 ZwClose(CardListHandle); 1067 } 1068 else 1069 { 1070 /* No key, no Card List */ 1071 PciRegistryInfo = NULL; 1072 } 1073 1074 /* Check if we failed to get the full structure */ 1075 if (!PciRegistryInfo) 1076 { 1077 /* Just allocate the basic structure then */ 1078 PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool, 1079 sizeof(PCI_REGISTRY_INFO_INTERNAL), 1080 TAG_HAL); 1081 if (!PciRegistryInfo) return NULL; 1082 } 1083 1084 /* Save the info we got */ 1085 PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision; 1086 PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision; 1087 PciRegistryInfo->NoBuses = PciRegInfo->NoBuses; 1088 PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism; 1089 PciRegistryInfo->ElementCount = ElementCount; 1090 1091 /* Return it */ 1092 return PciRegistryInfo; 1093 #else 1094 return NULL; 1095 #endif 1096 } 1097 1098 INIT_FUNCTION 1099 VOID 1100 NTAPI 1101 HalpInitializePciStubs(VOID) 1102 { 1103 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; 1104 UCHAR PciType; 1105 PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData; 1106 ULONG i; 1107 PCI_SLOT_NUMBER j; 1108 ULONG VendorId = 0; 1109 ULONG MaxPciBusNumber; 1110 1111 /* Query registry information */ 1112 PciRegistryInfo = HalpQueryPciRegistryInfo(); 1113 if (!PciRegistryInfo) 1114 { 1115 /* Assume type 1 */ 1116 PciType = 1; 1117 1118 /* Force a manual bus scan later */ 1119 MaxPciBusNumber = MAXULONG; 1120 } 1121 else 1122 { 1123 /* Get the PCI type */ 1124 PciType = PciRegistryInfo->HardwareMechanism & 0xF; 1125 1126 /* Get MaxPciBusNumber and make it 0-based */ 1127 MaxPciBusNumber = PciRegistryInfo->NoBuses - 1; 1128 1129 /* Free the info structure */ 1130 ExFreePoolWithTag(PciRegistryInfo, TAG_HAL); 1131 } 1132 1133 /* Initialize the PCI lock */ 1134 KeInitializeSpinLock(&HalpPCIConfigLock); 1135 1136 /* Check the type of PCI bus */ 1137 switch (PciType) 1138 { 1139 /* Type 1 PCI Bus */ 1140 case 1: 1141 1142 /* Copy the Type 1 handler data */ 1143 RtlCopyMemory(&PCIConfigHandler, 1144 &PCIConfigHandlerType1, 1145 sizeof(PCIConfigHandler)); 1146 1147 /* Set correct I/O Ports */ 1148 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT; 1149 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT; 1150 break; 1151 1152 /* Type 2 PCI Bus */ 1153 case 2: 1154 1155 /* Copy the Type 2 handler data */ 1156 RtlCopyMemory(&PCIConfigHandler, 1157 &PCIConfigHandlerType2, 1158 sizeof (PCIConfigHandler)); 1159 1160 /* Set correct I/O Ports */ 1161 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT; 1162 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT; 1163 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE; 1164 1165 /* Only 16 devices supported, not 32 */ 1166 BusData->MaxDevice = 16; 1167 break; 1168 1169 default: 1170 1171 /* Invalid type */ 1172 DbgPrint("HAL: Unknown PCI type\n"); 1173 } 1174 1175 /* Run a forced bus scan if needed */ 1176 if (MaxPciBusNumber == MAXULONG) 1177 { 1178 /* Initialize the max bus number to 0xFF */ 1179 HalpMaxPciBus = 0xFF; 1180 1181 /* Initialize the counter */ 1182 MaxPciBusNumber = 0; 1183 1184 /* Loop all possible buses */ 1185 for (i = 0; i < HalpMaxPciBus; i++) 1186 { 1187 /* Loop all devices */ 1188 for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++) 1189 { 1190 /* Query the interface */ 1191 if (HaliPciInterfaceReadConfig(NULL, 1192 i, 1193 j, 1194 &VendorId, 1195 0, 1196 sizeof(ULONG))) 1197 { 1198 /* Validate the vendor ID */ 1199 if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID) 1200 { 1201 /* Set this as the maximum ID */ 1202 MaxPciBusNumber = i; 1203 break; 1204 } 1205 } 1206 } 1207 } 1208 } 1209 1210 /* Set the real max bus number */ 1211 HalpMaxPciBus = MaxPciBusNumber; 1212 1213 /* We're done */ 1214 HalpPCIConfigInitialized = TRUE; 1215 } 1216 1217 /* EOF */ 1218 1219