/*++ Copyright (c) 1992 Microsoft Corporation Module Name: pci.c Abstract: WinDbg Extension Api Author: Ken Reneris (kenr) 18-August-1997 Environment: User Mode. Revision History: --*/ #include "precomp.h" #include "pci.h" #pragma hdrstop #define DUMP_VERBOSE 0x01 #define DUMP_TO_MAX_BUS 0x02 // from 0 to max #define DUMP_RAW_BYTES 0x04 // hex dump dump raw bytes #define DUMP_RAW_DWORDS 0x08 // hex dump dump raw dwords #define DUMP_ALLOW_INVALID_DEVICE 0x10 #define DUMP_ALLOW_INVALID_FUNCTION 0x20 #define DUMP_CAPABILITIES 0x40 #define DUMP_INTEL 0x80 #define DUMP_CONFIGSPACE 0x100 #define ANY 0xFF PSZ GetClassDesc(BYTE bBaseClass, BYTE bSubClass, BYTE bProgIF); UCHAR PCIDeref[4][4] = { {4,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; VOID DumpCfgSpace ( IN PPCI_COMMON_CONFIG pcs ); VOID HexDump ( IN ULONG indent, IN ULONG va, IN ULONG len, IN ULONG width, IN PUCHAR buf ) { UCHAR s[80], t[80]; PUCHAR ps, pt; ULONG i; static UCHAR rgHexDigit[] = "0123456789abcdef"; i = 0; // // If width = 4, dull dump, similar to debugger's dd command. // if (width == 4) { if (len & 3) { dprintf("hexdump internal error, dump dword, (len & 3) != 0\n"); // round up. len += 3; len &= ~3; } while (len) { if (i == 0) { dprintf("%*s%08x: ", indent, "", va); va += 16; } dprintf(" %08x", *(ULONG UNALIGNED *)buf); len -= 4; buf += 4; if (i == 3) { dprintf("\n"); i = 0; } else { i++; } } return; } if (width != 1) { dprintf ("hexdump internal error\n"); return ; } // // Width = 1, pretty dump, similar to debugger's db command. // while (len) { ps = s; pt = t; ps[0] = 0; pt[0] = '*'; pt++; for (i=0; i < 16; i++) { ps[0] = ' '; ps[1] = ' '; ps[2] = ' '; if (len) { ps[0] = rgHexDigit[buf[0] >> 4]; ps[1] = rgHexDigit[buf[0] & 0xf]; pt[0] = buf[0] < ' ' || buf[0] > 'z' ? '.' : buf[0]; len -= 1; buf += 1; pt += 1; } ps += 3; } ps[0] = 0; pt[0] = '*'; pt[1] = 0; s[23] = '-'; if (s[0]) { dprintf ("%*s%08lx: %s %s\n", indent, "", va, s, t); va += 16; } } } BOOL ReadPci ( IN PPCI_TYPE1_CFG_BITS PciCfg1, OUT PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ) { ULONG InputSize; ULONG IoSize; ULONG i; BUSDATA busData; PCI_SLOT_NUMBER slot; BOOL b; // // Zap input buffer // for (i=0; i < Length; i++) { Buffer[i] = 0xff; } // // It appears that we are only safe to call the HAL for reading // configuration space if the HAL has actually been initialized far // enough to do so. Since we have already hit a case where we hadnt // initialized everything and it crashed the debugger, we are restoring // X86 so that it reads configspace the way it always used to do. // // For non-X86 (i.e IA64) we are forced to call the HAL because we // currently have no other option. This means we may still crash on // those platforms in the case where // the HAL hasnt been initialized enough to handle it. // if (TargetMachine == IMAGE_FILE_MACHINE_I386) { while (Length) { PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); IoSize = sizeof(ULONG); #ifdef IG_IO_SPACE_RETURN b = #else b = TRUE; #endif WriteIoSpace64 ( PCI_TYPE1_ADDR_PORT, PciCfg1->u.AsULONG, &IoSize ); if (!b) { return FALSE; } IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; i = IoSize; ReadIoSpace64 ( PCI_TYPE1_DATA_PORT + (Offset % sizeof(ULONG)), (PULONG) Buffer, &i ); Offset += IoSize; Buffer += IoSize; Length -= IoSize; } }else{ // // Here we are going to call the debugger api that results in the // call to HalGetBusDataByOffset for the read. // // Note: This will crash the current debug session of attempted too // early in boot. // slot.u.AsULONG = 0; slot.u.bits.DeviceNumber = PciCfg1->u.bits.DeviceNumber; slot.u.bits.FunctionNumber = PciCfg1->u.bits.FunctionNumber; busData.BusDataType = PCIConfiguration; busData.BusNumber = PciCfg1->u.bits.BusNumber; busData.SlotNumber = slot.u.AsULONG; busData.Offset = Offset; busData.Buffer = Buffer; busData.Length = Length; // // Read it // #ifdef IG_IO_SPACE_RETURN b = #else b = TRUE; #endif Ioctl(IG_GET_BUS_DATA, &busData, sizeof(busData)); if (!b) { return FALSE; } } return TRUE; } BOOLEAN WritePci ( IN PPCI_TYPE1_CFG_BITS PciCfg1, IN PUCHAR Buffer, IN ULONG Offset, IN ULONG Length ) { ULONG IoSize; ULONG i; BUSDATA busData; PCI_SLOT_NUMBER slot; if (TargetMachine == IMAGE_FILE_MACHINE_I386) { // // For the same reasons as the read, we are only calling the HAL // on non-x86 targets for now. // while (Length) { PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); IoSize = sizeof(ULONG); WriteIoSpace64 ((ULONG) PCI_TYPE1_ADDR_PORT, PciCfg1->u.AsULONG, &IoSize ); IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; i = IoSize; WriteIoSpace64 ( PCI_TYPE1_DATA_PORT + (Offset % sizeof(ULONG)), *(PULONG)Buffer, &i); Offset += IoSize; Buffer += IoSize; Length -= IoSize; } }else{ slot.u.AsULONG = 0; slot.u.bits.DeviceNumber = PciCfg1->u.bits.DeviceNumber; slot.u.bits.FunctionNumber = PciCfg1->u.bits.FunctionNumber; busData.BusDataType = PCIConfiguration; busData.BusNumber = PciCfg1->u.bits.BusNumber; busData.SlotNumber = slot.u.AsULONG; busData.Offset = Offset; busData.Buffer = Buffer; busData.Length = Length; // // Write it // if (!(Ioctl(IG_SET_BUS_DATA, &busData, sizeof(busData)))){ return FALSE; } } return TRUE; } VOID DumpPciBar ( IN ULONG barno, IN ULONG indent, IN ULONG bar, IN OUT PULONG state ) { ULONG type, i; CHAR m[20], str[80]; if (bar) { if (bar & 1) { sprintf (str, "IO[%d]:%x ", barno, bar); } else { type = (bar >> 1) & 0x3; if (bar & 8) { strcpy (m, "MPF"); } else { strcpy (m, "MEM"); } if (type == 0x01) { m[1] = '1'; // less then 1M } sprintf (str, "%s[%d]:%x ", m, barno, bar); if (type == 0x10) { dprintf ("warning - 64bit bar not decoded\n"); *state = 0; } if (type == 0x11) { dprintf ("bar type is reserved\n"); *state = 0; } } if (!*state) { dprintf ("%*s", indent, ""); } i = strlen(str); dprintf("%s%*s", str, 17-i, ""); *state += i; } } VOID DumpPciType2Bar( IN BOOLEAN barIsIo, IN BOOLEAN barIsBase, IN ULONG barno, IN ULONG indent, IN ULONG bar, IN OUT PULONG state ) { ULONG i; CHAR str[80]; if (bar) { if (barIsIo) { sprintf (str, "IO[%d].%s:%x ", barno, (barIsBase?"base":"limit"), bar); } else { sprintf (str, "MEM[%d].%s:%x ", barno, (barIsBase?"base":"limit"), bar); } if (!*state) { dprintf("%*s", indent, ""); } i = strlen(str); dprintf("%s%*s", str, 17-i, ""); *state += i; } } VOID DumpPciBarComplete( IN OUT PULONG state ) { if (*state) { dprintf ("\n"); *state = 0; } } VOID DumpCapabilities( IN UCHAR CapPtr, IN PPCI_TYPE1_CFG_BITS PciCfg1 ) { union _cap_buffer { PCI_CAPABILITIES_HEADER header; PCI_PM_CAPABILITY pm; PCI_AGP_CAPABILITY agp; } cap; PCHAR ts; ULONG t; do { if (CapPtr < PCI_COMMON_HDR_LENGTH) { dprintf(" Error: Capability pointer 0x%02x points to common header (invalid).\n", CapPtr ); break; } if (CapPtr & 0x3) { dprintf(" Error: Capability pointer 0x%02x not DWORD aligned (invalid).\n", CapPtr ); break; } ReadPci ( PciCfg1, (PUCHAR)&cap, CapPtr, sizeof(cap.header) ); switch (cap.header.CapabilityID) { case PCI_CAPABILITY_ID_POWER_MANAGEMENT: ReadPci ( PciCfg1, (PUCHAR)&cap, CapPtr, sizeof(cap.pm) ); t = cap.pm.PMC.AsUSHORT; dprintf(" Cap[%02x] ID %02x \n", CapPtr, cap.header.CapabilityID ); dprintf(" PMC %04x (%s%s%s%s%s%s %s%s%s%s%s%sv%x)\n", t, t & 0xf800 ? "PME from D" : "", t & 0x8000 ? "3C" : "", t & 0x4000 ? "3H" : "", t & 0x2000 ? "2" : "", t & 0x1000 ? "1" : "", t & 0x0800 ? "0" : "", t & 0x0600 ? "Supports D" : "", cap.pm.PMC.Capabilities.Support.D2 ? "2" : "", cap.pm.PMC.Capabilities.Support.D1 ? "1" : "", t & 0x0600 ? " " : "", cap.pm.PMC.Capabilities.DeviceSpecificInitialization ? "DSI " : "", cap.pm.PMC.Capabilities.PMEClock ? "PME needs Clock, " : "", cap.pm.PMC.Capabilities.Version ); t &= 0x01d0; if (t) { dprintf(" WARNING PMC non-zero reserved fields %04x\n", t ); } t = cap.pm.PMCSR.AsUSHORT; dprintf(" PMCSR %04x (PME_Status=%d PME_En=%d State=D%d%s)\n", t, cap.pm.PMCSR.ControlStatus.PMEStatus, cap.pm.PMCSR.ControlStatus.PMEEnable, cap.pm.PMCSR.ControlStatus.PowerState, cap.pm.PMCSR.ControlStatus.PowerState == 3 ? "hot" : "" ); // // Here would be a good time to run // run down the data registers if // they exist. // break; case PCI_CAPABILITY_ID_AGP: ReadPci ( PciCfg1, (PUCHAR)&cap, CapPtr, sizeof(cap.agp) ); switch (cap.agp.AGPStatus.Rate) { case 1: ts = "1X"; break; case 2: ts = "2X"; break; case 3: ts = "1,2X"; break; default: ts = ""; break; } t = *(PULONG)&cap.agp.AGPStatus; dprintf(" Cap[%02x] ID %02x AGP mj/mn=%x/%x\n", CapPtr, cap.header.CapabilityID, cap.agp.Major, cap.agp.Minor ); dprintf(" Status %08x (Rq:%02x SBA:%x Rate:%x (%s))\n", t, cap.agp.AGPStatus.RequestQueueDepthMaximum, cap.agp.AGPStatus.SideBandAddressing, cap.agp.AGPStatus.Rate, ts ); switch (cap.agp.AGPCommand.Rate) { case 1: ts = "1X"; break; case 2: ts = "2X"; break; case 4: ts = "4X"; break; default: ts = ""; break; } t = *(PULONG)&cap.agp.AGPCommand; dprintf(" Command %08x (Rq:%02x SBA:%x AGP:%x Rate:%x (%s)\n", t, cap.agp.AGPCommand.RequestQueueDepth, cap.agp.AGPCommand.SBAEnable, cap.agp.AGPCommand.AGPEnable, cap.agp.AGPCommand.Rate, ts ); break; default: break; } CapPtr = cap.header.Next; } while (CapPtr != 0); } VOID pcidump ( IN ULONG Flags, IN ULONG MinBus, IN ULONG MaxBus, IN ULONG MinDevice, IN ULONG MaxDevice, IN ULONG MinFunction, IN ULONG MaxFunction, IN ULONG MinAddr, IN ULONG MaxAddr ) { ULONG Bus, Device, Function; PCI_TYPE1_CFG_BITS PciCfg1; PCI_COMMON_CONFIG PciHdr; BOOLEAN BusHeader, SkipLine, BarIsIo; ULONG Type, Len, i; UCHAR s[40]; PUCHAR Buf; ULONG state; ULONG bar, barno; if (MinBus > 0xFF || MaxBus > 0xFF || MinDevice > PCI_MAX_DEVICES || MaxDevice > PCI_MAX_DEVICES || MinFunction > PCI_MAX_FUNCTION || MaxFunction > PCI_MAX_FUNCTION || MinAddr > 0xFF || MaxAddr > 0x100 || MinAddr > MaxAddr) { dprintf ("Bad pci dump parameter\n"); //dprintf ("Flags %d MinBus %d MaxBus %d\n", Flags, MinBus, MaxBus); //dprintf ("MinDev %d MaxDev %d MinFnc %d MinFnc %d\n", MinDevice, MaxDevice, MinFunction, MaxFunction); return ; } //dprintf ("Flags %d MinAddr %d MaxAddr %d\n", Flags, MinAddr, MaxAddr); for (Bus=MinBus; Bus <= MaxBus; Bus++) { BusHeader = FALSE; for (Device=MinDevice; Device <= MaxDevice; Device++) { if (CheckControlC()) { return; } // // Read the device ID // PciCfg1.u.AsULONG = 0; PciCfg1.u.bits.BusNumber = Bus; PciCfg1.u.bits.DeviceNumber = Device; PciCfg1.u.bits.FunctionNumber = 0; PciCfg1.u.bits.Enable = TRUE; ReadPci (&PciCfg1, (PUCHAR) &PciHdr, 0, sizeof(ULONG)); // // If not a valid ID, skip to next device if (PciHdr.VendorID == PCI_INVALID_VENDORID) { if (!(Flags & DUMP_ALLOW_INVALID_DEVICE)) { dprintf ("%02x\r", Device); continue; } } for (Function=MinFunction; Function <= MaxFunction; Function++) { if (CheckControlC()) { return; } PciCfg1.u.bits.FunctionNumber = Function; // // Read device ID // if (Function) { ReadPci (&PciCfg1, (PUCHAR) &PciHdr, 0, sizeof(ULONG)); } if (PciHdr.VendorID == PCI_INVALID_VENDORID) { if (!(Flags & DUMP_ALLOW_INVALID_DEVICE)) { continue; } } // // Dump ID // if (!BusHeader) { dprintf ("PCI Bus %d\n", Bus); BusHeader = TRUE; } dprintf ("%02x:%x %04x:%04x", Device, Function, PciHdr.VendorID, PciHdr.DeviceID ); // // Read the rest of the common header // ReadPci ( &PciCfg1, ((PUCHAR) &PciHdr) + sizeof(ULONG), 0 + sizeof(ULONG), PCI_COMMON_HDR_LENGTH ); Type = PciHdr.HeaderType & ~PCI_MULTIFUNCTION; if (Type == 0x7f && PciHdr.BaseClass == 0xff && PciHdr.SubClass == 0xff) { if (!(Flags & DUMP_ALLOW_INVALID_FUNCTION)) { dprintf (" bogus, skipping rest of device\n"); break; } } // // Dump it // s[0] = PciHdr.Command & PCI_ENABLE_IO_SPACE ? 'i' : '.'; s[1] = PciHdr.Command & PCI_ENABLE_MEMORY_SPACE ? 'm' : '.'; s[2] = PciHdr.Command & PCI_ENABLE_BUS_MASTER ? 'b' : '.'; s[3] = PciHdr.Command & PCI_ENABLE_VGA_COMPATIBLE_PALETTE ? 'v' : '.'; s[4] = PciHdr.Command & PCI_ENABLE_PARITY ? 'p' : '.'; s[5] = PciHdr.Command & PCI_ENABLE_SERR ? 's' : '.'; s[6] = 0; dprintf (".%02x Cmd[%04x:%s] ", PciHdr.RevisionID, PciHdr.Command, s); s[0] = PciHdr.Status & PCI_STATUS_CAPABILITIES_LIST ? 'c' : '.'; s[1] = PciHdr.Status & PCI_STATUS_66MHZ_CAPABLE ? '6' : '.'; s[2] = PciHdr.Status & PCI_STATUS_DATA_PARITY_DETECTED ? 'P' : '.'; s[3] = PciHdr.Status & PCI_STATUS_SIGNALED_TARGET_ABORT ? 'A' : '.'; s[4] = PciHdr.Status & PCI_STATUS_SIGNALED_SYSTEM_ERROR ? 'S' : '.'; s[5] = 0; dprintf ("Sts[%04x:%s] ", PciHdr.Status, s); switch (Type) { case PCI_DEVICE_TYPE: dprintf ("Device"); if (PciHdr.u.type0.SubVendorID || PciHdr.u.type0.SubSystemID) { dprintf (" SubID:%04x:%04x", PciHdr.u.type0.SubVendorID, PciHdr.u.type0.SubSystemID ); } break; case PCI_BRIDGE_TYPE: dprintf ("PciBridge %d->%d-%d", PciHdr.u.type1.PrimaryBus, PciHdr.u.type1.SecondaryBus, PciHdr.u.type1.SubordinateBus ); break; case PCI_CARDBUS_BRIDGE_TYPE: dprintf ("CardbusBridge %d->%d-%d", PciHdr.u.type2.PrimaryBus, PciHdr.u.type2.SecondaryBus, PciHdr.u.type2.SubordinateBus ); break; default: dprintf ("type %x", Type); break; } // // Search for a class code match // PCHAR Desc = GetClassDesc(PciHdr.BaseClass, PciHdr.SubClass, PciHdr.ProgIf); if (Desc) { dprintf (" %s", Desc); } else { dprintf (" Class:%x:%x:%x", PciHdr.BaseClass, PciHdr.SubClass, PciHdr.ProgIf ); } dprintf ("\n"); SkipLine = FALSE; if (Flags & DUMP_VERBOSE) { SkipLine = TRUE; PciCfg1.u.bits.RegisterNumber = 0; switch (Type) { case PCI_DEVICE_TYPE: dprintf (" cf8:%x IntPin:%x IntLine:%x Rom:%x cis:%x cap:%x\n", PciCfg1.u.AsULONG, PciHdr.u.type0.InterruptPin, PciHdr.u.type0.InterruptLine, PciHdr.u.type0.ROMBaseAddress, PciHdr.u.type0.CIS, PciHdr.u.type0.CapabilitiesPtr ); state = 0; for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { bar = PciHdr.u.type0.BaseAddresses[i]; DumpPciBar(i, 6, bar, &state); } DumpPciBarComplete(&state); break; case PCI_BRIDGE_TYPE: i = PciHdr.u.type1.BridgeControl; dprintf (" cf8:%x IntPin:%x IntLine:%x Rom:%x cap:%x 2sts:%x BCtrl:%x%s%s%s\n", PciCfg1.u.AsULONG, PciHdr.u.type1.InterruptPin, PciHdr.u.type1.InterruptLine, PciHdr.u.type1.ROMBaseAddress, PciHdr.u.type1.CapabilitiesPtr, PciHdr.u.type1.SecondaryStatus, PciHdr.u.type1.BridgeControl, i & PCI_ENABLE_BRIDGE_VGA ? " VGA" : "", i & PCI_ENABLE_BRIDGE_ISA ? " ISA" : "", i & PCI_ASSERT_BRIDGE_RESET ? " RESET" : "" ); dprintf (" IO:%x-%x Mem:%x-%x PMem:%x-%x\n", PciBridgeIO2Base (PciHdr.u.type1.IOBase, PciHdr.u.type1.IOBaseUpper16), PciBridgeIO2Limit(PciHdr.u.type1.IOLimit, PciHdr.u.type1.IOLimitUpper16), PciBridgeMemory2Base (PciHdr.u.type1.MemoryBase), PciBridgeMemory2Limit(PciHdr.u.type1.MemoryLimit), PciBridgeMemory2Base (PciHdr.u.type1.PrefetchBase), PciBridgeMemory2Limit(PciHdr.u.type1.PrefetchLimit) ); state = 0; for (i=0; i < PCI_TYPE1_ADDRESSES; i++) { bar = PciHdr.u.type1.BaseAddresses[i]; DumpPciBar(i, 6, bar, &state); } DumpPciBarComplete(&state); break; case PCI_CARDBUS_BRIDGE_TYPE: i = PciHdr.u.type2.BridgeControl; dprintf (" cf8:%x IntPin:%x IntLine:%x SocketRegBase:%x cap:%x 2sts:%x BCtrl:%x%s%s%s\n", PciCfg1.u.AsULONG, PciHdr.u.type2.InterruptPin, PciHdr.u.type2.InterruptLine, PciHdr.u.type2.SocketRegistersBaseAddress, PciHdr.u.type2.CapabilitiesPtr, PciHdr.u.type2.SecondaryStatus, PciHdr.u.type2.BridgeControl, i & PCI_ENABLE_BRIDGE_VGA ? " VGA" : "", i & PCI_ENABLE_BRIDGE_ISA ? " ISA" : "", i & PCI_ASSERT_BRIDGE_RESET ? " RESET" : "" ); dprintf("\n"); state=0; for (i = 0; i < (PCI_TYPE2_ADDRESSES - 1); i++) { bar = PciHdr.u.type2.Range[i].Base; // // First 2 BARs (base+limit) are memory // BarIsIo = (i > 1); barno = i; if (BarIsIo) { barno -= 2; } DumpPciType2Bar(BarIsIo,TRUE, barno, 6, bar, &state); bar = PciHdr.u.type2.Range[i].Limit; DumpPciType2Bar(BarIsIo, FALSE, i, 6, bar, &state); } DumpPciBarComplete(&state); break; } } // // Dump CAPABILITIES if any. // if (Flags & DUMP_CAPABILITIES) { if (PciHdr.Status & PCI_STATUS_CAPABILITIES_LIST) { UCHAR capPtr = 0; SkipLine = TRUE; switch (Type) { case PCI_DEVICE_TYPE: capPtr = PciHdr.u.type0.CapabilitiesPtr; break; case PCI_BRIDGE_TYPE: capPtr = PciHdr.u.type1.CapabilitiesPtr; break; case PCI_CARDBUS_BRIDGE_TYPE: capPtr = PciHdr.u.type2.CapabilitiesPtr; break; } if (capPtr != 0) { DumpCapabilities(capPtr, &PciCfg1); } else { // // Capabilities flag is set in Status but // pointer is 0??? Something's broken. // dprintf(" Warning: Capability bit set in Status but capability pointer is 0.\n"); } } } // // Dump hex bytes // if (Flags & DUMP_RAW_BYTES) { ULONG w; // // Raw dump requested, if no range default to common // config. // if (!MinAddr && !MaxAddr) { MaxAddr = PCI_COMMON_HDR_LENGTH - 1; } // // Default width to 1. If dumping dwords, set width // width to 4 and round min and max accordingly. // w = 1; if (Flags & DUMP_RAW_DWORDS) { w = 4; MinAddr &= ~3; MaxAddr &= ~3; MaxAddr += 3; } Buf = ((PUCHAR) &PciHdr) + MinAddr; Len = MaxAddr - MinAddr + 1; if (MinAddr <= PCI_COMMON_HDR_LENGTH) { if (MaxAddr > PCI_COMMON_HDR_LENGTH) { ReadPci ( &PciCfg1, PciHdr.DeviceSpecific, PCI_COMMON_HDR_LENGTH, MaxAddr - PCI_COMMON_HDR_LENGTH ); } } else { ReadPci (&PciCfg1, Buf, MinAddr, Len); } HexDump (w == 4 ? 6 : 1, MinAddr, Len, w, Buf); SkipLine = TRUE; } else if ((Flags & DUMP_INTEL) && PciHdr.VendorID == 0x8086) { Buf = PciHdr.DeviceSpecific; Len = sizeof (PciHdr) - PCI_COMMON_HDR_LENGTH; ReadPci (&PciCfg1, Buf, PCI_COMMON_HDR_LENGTH, Len); HexDump (1, PCI_COMMON_HDR_LENGTH, Len, 1, Buf); SkipLine = TRUE; } if (Flags & DUMP_CONFIGSPACE) { PCI_COMMON_CONFIG cs; ReadPci(&PciCfg1, (PUCHAR)&cs, 0, sizeof(cs)); dprintf ("Config Space:\n", PciCfg1.u.bits.BusNumber, PciCfg1.u.bits.DeviceNumber, PciCfg1.u.bits.FunctionNumber); DumpCfgSpace(&cs); dprintf ("\n"); } if (SkipLine) { dprintf ("\n"); } // // If no more functions on this device, skip the rest // of the functions // if (Function == 0 && !(PciHdr.HeaderType & PCI_MULTIFUNCTION)) { if (!(Flags & DUMP_ALLOW_INVALID_FUNCTION)) { break; } } } } } } DECLARE_API( pci ) /*++ Routine Description: Dumps pci type2 config data Arguments: args - Supplies the address in hex. Return Value: None --*/ { LONG noargs; ULONG Flags; ULONG MinBus, MaxBus; ULONG Device, MinDevice, MaxDevice; ULONG Function, MinFunction, MaxFunction; ULONG MinAddr, MaxAddr; MinBus = 0; MaxBus = 0; MinDevice = 0; MaxDevice = PCI_MAX_DEVICES - 1; MinFunction = 0; MaxFunction = PCI_MAX_FUNCTION - 1; MinAddr = 0; MaxAddr = 0; Flags = 0; if (g_TargetQual == DEBUG_DUMP_SMALL || g_TargetQual == DEBUG_DUMP_DEFAULT || g_TargetQual == DEBUG_DUMP_FULL) { dprintf("!pci does not work for dump targets\n"); return E_INVALIDARG; } { INIT_API(); noargs = sscanf(args,"%lX %lX %lX %lX %lX %lX", &Flags, // 1 &MaxBus, // 2 &Device, // 3 &Function, // 4 &MinAddr, // 5 &MaxAddr // 6 ); MinBus = MaxBus; if (Flags & DUMP_TO_MAX_BUS) { MinBus = 0; } if (noargs >= 3) { Flags |= DUMP_ALLOW_INVALID_DEVICE; MinDevice = Device; MaxDevice = Device; } if (noargs >= 4) { MinFunction = Function; MaxFunction = Function; } if (MinAddr || MaxAddr) { Flags |= DUMP_RAW_BYTES; } if (Flags & DUMP_RAW_DWORDS) { Flags |= DUMP_RAW_BYTES; } pcidump ( Flags, MinBus, MaxBus, MinDevice, MaxDevice, MinFunction, MaxFunction, MinAddr, MaxAddr ); EXIT_API(); } return S_OK; }