1303 lines
52 KiB
C#
1303 lines
52 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: PciConfig.cs
|
|
//
|
|
// Note:
|
|
//
|
|
|
|
#define VERBOSE
|
|
//#define DEBUG_PCI
|
|
|
|
using System;
|
|
using StringBuilder = System.Text.StringBuilder;
|
|
using System.Collections;
|
|
using Microsoft.Singularity;
|
|
|
|
namespace Microsoft.Singularity.Io
|
|
{
|
|
[CLSCompliant(false)]
|
|
public class PciConfig : IoConfig
|
|
{
|
|
//
|
|
// Bit encodings for PCI_COMMON_CONFIG.HeaderType
|
|
//
|
|
|
|
public const uint PCI_MULTIFUNCTION = 0x800000; // full dword
|
|
public const uint PCI_TYPE_MASK = 0x7f0000; // full dword
|
|
public const uint PCI_DEVICE_TYPE = 0x000000; // full dword
|
|
public const uint PCI_BRIDGE_TYPE = 0x010000; // full dword
|
|
public const uint PCI_CARDBUS_TYPE = 0x020000; // full dword
|
|
|
|
//
|
|
// Bit encodings for PCI_COMMON_CONFIG.Control
|
|
//
|
|
public const uint PCI_CONFIG_Command = 0x0004;
|
|
|
|
public const uint PCI_ENABLE_IO_SPACE = 0x0001;
|
|
public const uint PCI_ENABLE_MEMORY_SPACE = 0x0002;
|
|
public const uint PCI_ENABLE_BUS_MASTER = 0x0004;
|
|
const uint PCI_ENABLE_SPECIAL_CYCLES = 0x0008;
|
|
const uint PCI_ENABLE_WRITE_AND_INVALIDATE = 0x0010;
|
|
const uint PCI_ENABLE_VGA_COMPATIBLE_PALETTE = 0x0020;
|
|
const uint PCI_ENABLE_PARITY = 0x0040; // (ro+)
|
|
const uint PCI_ENABLE_WAIT_CYCLE = 0x0080; // (ro+)
|
|
const uint PCI_ENABLE_SERR = 0x0100; // (ro+)
|
|
const uint PCI_ENABLE_FAST_BACK_TO_BACK = 0x0200; // (ro)
|
|
const uint PCI_DISABLE_INTERRUPTS = 0x0400;
|
|
|
|
//
|
|
// Bit encodings for PCI_COMMON_CONFIG.Status
|
|
//
|
|
const uint PCI_STATUS_FAST_BACK_TO_BACK = 0x0080; // (ro)
|
|
const uint PCI_STATUS_DATA_PARITY_DETECTED = 0x0100;
|
|
const uint PCI_STATUS_DEVSEL = 0x0600; // 2 bits wide
|
|
const uint PCI_STATUS_SIGNALED_TARGET_ABORT = 0x0800;
|
|
const uint PCI_STATUS_RECEIVED_TARGET_ABORT = 0x1000;
|
|
const uint PCI_STATUS_RECEIVED_MASTER_ABORT = 0x2000;
|
|
const uint PCI_STATUS_SIGNALED_SYSTEM_ERROR = 0x4000;
|
|
const uint PCI_STATUS_DETECTED_PARITY_ERROR = 0x8000;
|
|
|
|
// Bit encodes for PCI_COMMON_CONFIG.u.type0.BaseAddresses
|
|
//
|
|
const uint PCI_ADDRESS_IO_SPACE = 0x00000001; // (ro)
|
|
const uint PCI_ADDRESS_MEMORY_TYPE_MASK = 0x00000006; // (ro)
|
|
const uint PCI_ADDRESS_MEMORY_PREFETCHABLE = 0x00000008; // (ro)
|
|
|
|
const uint PCI_TYPE_32BIT = 0;
|
|
const uint PCI_TYPE_20BIT = 2;
|
|
const uint PCI_TYPE_64BIT = 4;
|
|
|
|
const uint PCI_ROMADDRESS_ENABLED = 0x00000001;
|
|
|
|
const uint PCI_ENABLE_BRIDGE_PARITY_ERROR = 0x0001;
|
|
const uint PCI_ENABLE_BRIDGE_SERR = 0x0002;
|
|
const uint PCI_ENABLE_BRIDGE_ISA = 0x0004;
|
|
const uint PCI_ENABLE_BRIDGE_VGA = 0x0008;
|
|
const uint PCI_ENABLE_BRIDGE_MASTER_ABORT_SERR = 0x0020;
|
|
const uint PCI_ASSERT_BRIDGE_RESET = 0x0040;
|
|
const uint PCI_ENABLE_BRIDGE_FAST_BACK_TO_BACK = 0x0080;
|
|
|
|
const byte PCI_CLASS_STORAGE = 0x01;
|
|
const byte PCI_CLASS_NETWORK = 0x02;
|
|
const byte PCI_CLASS_DISPLAY = 0x03;
|
|
const byte PCI_CLASS_MULTIMEDIA = 0x04;
|
|
const byte PCI_CLASS_MEMORY = 0x05;
|
|
const byte PCI_CLASS_BRIDGE = 0x06;
|
|
const byte PCI_CLASS_COMMUNICATION = 0x07;
|
|
const byte PCI_CLASS_SYSTEM = 0x08;
|
|
const byte PCI_CLASS_INPUT = 0x09;
|
|
const byte PCI_CLASS_DOCKING = 0x0a;
|
|
const byte PCI_CLASS_PROCESSOR = 0x0b;
|
|
const byte PCI_CLASS_SERIAL = 0x0c;
|
|
const byte PCI_CLASS_WIRELESS = 0x0d;
|
|
const byte PCI_CLASS_I2O = 0x0e;
|
|
const byte PCI_CLASS_SATELLITE = 0x0f;
|
|
const byte PCI_CLASS_ENCRYPTION = 0x10;
|
|
const byte PCI_CLASS_ACQUISITION = 0x11;
|
|
const byte PCI_CLASS_OTHERS = 0xff;
|
|
|
|
const byte PCI_CLASS_STORAGE_SCSI = 0x00;
|
|
const byte PCI_CLASS_STORAGE_IDE = 0x01; // NB: Interface
|
|
const byte PCI_CLASS_STORAGE_FLOPPY = 0x02;
|
|
const byte PCI_CLASS_STORAGE_IPI = 0x03;
|
|
const byte PCI_CLASS_STORAGE_RAID = 0x04;
|
|
const byte PCI_CLASS_STORAGE_ATA = 0x05; // NB: Interface
|
|
const byte PCI_CLASS_STORAGE_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_NETWORK_ETHERNET = 0x00;
|
|
const byte PCI_CLASS_NETWORK_RING = 0x01;
|
|
const byte PCI_CLASS_NETWORK_FDDI = 0x02;
|
|
const byte PCI_CLASS_NETWORK_ATM = 0x03;
|
|
const byte PCI_CLASS_NETWORK_ISDN = 0x04;
|
|
const byte PCI_CLASS_NETWORK_FIP = 0x05;
|
|
const byte PCI_CLASS_NETWORK_PICMG = 0x06; // NB: Interface
|
|
const byte PCI_CLASS_NETWORK_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_DISPLAY_VGA = 0x00; // NB: Interface
|
|
const byte PCI_CLASS_DISPLAY_XGA = 0x01;
|
|
const byte PCI_CLASS_DISPLAY_3D = 0x02;
|
|
const byte PCI_CLASS_DISPLAY_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_MULTIMEDIA_VIDEO = 0x00;
|
|
const byte PCI_CLASS_MULTIMEDIA_AUDIO = 0x01;
|
|
const byte PCI_CLASS_MULTIMEDIA_TELEPHONY = 0x02;
|
|
const byte PCI_CLASS_MULTIMEDIA_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_MEMORY_RAM = 0x00;
|
|
const byte PCI_CLASS_MEMORY_FLASH = 0x01;
|
|
const byte PCI_CLASS_MEMORY_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_BRIDGE_HOST = 0x00;
|
|
const byte PCI_CLASS_BRIDGE_ISA = 0x01;
|
|
const byte PCI_CLASS_BRIDGE_EISA = 0x02;
|
|
const byte PCI_CLASS_BRIDGE_MC = 0x03;
|
|
const byte PCI_CLASS_BRIDGE_PCI = 0x04; // NB: Interface
|
|
const byte PCI_CLASS_BRIDGE_PCMCIA = 0x05;
|
|
const byte PCI_CLASS_BRIDGE_NUBUS = 0x06;
|
|
const byte PCI_CLASS_BRIDGE_CARDBUS = 0x07;
|
|
const byte PCI_CLASS_BRIDGE_RACEWAY = 0x08; // NB: Interface
|
|
const byte PCI_CLASS_BRIDGE_SEMIPCI = 0x09; // NB: Interface
|
|
const byte PCI_CLASS_BRIDGE_INFINIBAND = 0x0a;
|
|
const byte PCI_CLASS_BRIDGE_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_COMMUNICATION_SERIAL = 0x00; // NB: Interface
|
|
const byte PCI_CLASS_COMMUNICATION_PARALLEL = 0x01; // NB: Interface
|
|
const byte PCI_CLASS_COMMUNICATION_MULTIPORT = 0x02;
|
|
const byte PCI_CLASS_COMMUNICATION_MODEM = 0x03; // NB: Interface
|
|
const byte PCI_CLASS_COMMUNICATION_GPIB = 0x04;
|
|
const byte PCI_CLASS_COMMUNICATION_SMARTCARD = 0x05;
|
|
const byte PCI_CLASS_COMMUNICATION_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_SYSTEM_PIC = 0x00; // NB: Interface
|
|
const byte PCI_CLASS_SYSTEM_DMA = 0x01; // NB: Interface
|
|
const byte PCI_CLASS_SYSTEM_TIMER = 0x02; // NB: Interface
|
|
const byte PCI_CLASS_SYSTEM_RTC = 0x03; // NB: Interface
|
|
const byte PCI_CLASS_SYSTEM_PCIHP = 0x04;
|
|
const byte PCI_CLASS_SYSTEM_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_INPUT_KEYBOARD = 0x00;
|
|
const byte PCI_CLASS_INPUT_PEN = 0x01;
|
|
const byte PCI_CLASS_INPUT_MOUSE = 0x02;
|
|
const byte PCI_CLASS_INPUT_SCANNER = 0x03;
|
|
const byte PCI_CLASS_INPUT_GAMEPORT = 0x04; // NB: Interface
|
|
const byte PCI_CLASS_INPUT_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_SERIAL_FIREWIRE = 0x00; // NB: Interface
|
|
const byte PCI_CLASS_SERIAL_ACCESS = 0x01;
|
|
const byte PCI_CLASS_SERIAL_SSA = 0x02;
|
|
const byte PCI_CLASS_SERIAL_USB = 0x03; // NB: Interface
|
|
const byte PCI_CLASS_SERIAL_FIBRE = 0x04;
|
|
const byte PCI_CLASS_SERIAL_SMBUS = 0x05;
|
|
const byte PCI_CLASS_SERIAL_INFINIBAND = 0x06;
|
|
const byte PCI_CLASS_SERIAL_IPMI = 0x07; // NB: Interface
|
|
const byte PCI_CLASS_SERIAL_SERCOS = 0x08;
|
|
const byte PCI_CLASS_SERIAL_CANBUS = 0x09;
|
|
|
|
const byte PCI_CLASS_WIRELESS_IRDA = 0x00;
|
|
const byte PCI_CLASS_WIRELESS_IR = 0x01;
|
|
const byte PCI_CLASS_WIRELESS_RF = 0x10;
|
|
const byte PCI_CLASS_WIRELESS_BLUETOOTH = 0x11;
|
|
const byte PCI_CLASS_WIRELESS_BROADBAND = 0x12;
|
|
const byte PCI_CLASS_WIRELESS_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_I2O_I2O = 0x00; // NB: Interface
|
|
|
|
const byte PCI_CLASS_SATELLITE_TV = 0x01;
|
|
const byte PCI_CLASS_SATELLITE_AUDIO = 0x02;
|
|
const byte PCI_CLASS_SATELLITE_VOICE = 0x03;
|
|
const byte PCI_CLASS_SATELLITE_DATA = 0x04;
|
|
|
|
const byte PCI_CLASS_ENCRYPTION_NETWORK = 0x00;
|
|
const byte PCI_CLASS_ENCRYPTION_ENTERTAINMENT = 0x10;
|
|
const byte PCI_CLASS_ENCRYPTION_OTHER = 0x80;
|
|
|
|
const byte PCI_CLASS_ACQUISITION_DPIO = 0x00;
|
|
const byte PCI_CLASS_ACQUISITION_PERF = 0x01;
|
|
const byte PCI_CLASS_ACQUISITION_COMM = 0x10;
|
|
const byte PCI_CLASS_ACQUISITION_MGMT = 0x20;
|
|
const byte PCI_CLASS_ACQUISITION_OTHER = 0x80;
|
|
|
|
const int PCI_INTERRUPT_LINE = 0x3c;
|
|
|
|
const int PCI_INTERRUPT_PIN = 0x3d;
|
|
const byte PCI_INTERRUPT_PIN_A = 1;
|
|
const byte PCI_INTERRUPT_PIN_B = 2;
|
|
const byte PCI_INTERRUPT_PIN_C = 3;
|
|
const byte PCI_INTERRUPT_PIN_D = 4;
|
|
|
|
protected PciPort port;
|
|
|
|
public ushort VendorId; // 00..01 (ro)
|
|
public ushort DeviceId; // 02..03 (ro)
|
|
public ushort Control; // 04..05 Device control
|
|
public ushort Status; // 06..07
|
|
protected byte RevisionId; // 08..08 (ro)
|
|
public byte Interface; // 09..09 (ro)
|
|
protected byte SubClassId; // 0a..0a (ro)
|
|
protected byte ClassId; // 0b..0b (ro)
|
|
public byte CacheLineSize; // 0c..0c (ro+)
|
|
protected byte LatencyTimer; // 0d..0d (ro+)
|
|
protected byte HeaderType; // 0e..0e (ro)
|
|
protected byte BIST; // 0f..0f Built in self test
|
|
|
|
protected uint[] BaseAddresses; // 10..17 or ..27 [2 or 6]
|
|
protected uint[] BaseAddrSizes;
|
|
|
|
protected ushort SubsystemVendorId; // 2c..2d (devices only)
|
|
protected ushort SubsystemDeviceId; // 2e..2f (devices only)
|
|
|
|
protected uint ROMBaseAddress; // 38..3b or 30.33
|
|
protected byte InterruptPin; // 3d..3d
|
|
|
|
public static PciConfig Create(String[] ids, PciPort port,
|
|
IoRange [] fixedRanges)
|
|
{
|
|
uint u = port.Read32(0);
|
|
if (u == ~0u || u == 0) {
|
|
return null;
|
|
}
|
|
|
|
PciConfig config = null;
|
|
|
|
u = port.Read32(0x0c);
|
|
switch (u & PciConfig.PCI_TYPE_MASK) {
|
|
case PciConfig.PCI_DEVICE_TYPE:
|
|
config = new PciDeviceConfig(port);
|
|
break;
|
|
case PciConfig.PCI_BRIDGE_TYPE:
|
|
config = new PciBridgeConfig(port);
|
|
break;
|
|
case PciConfig.PCI_CARDBUS_TYPE:
|
|
config = new PciCardbusConfig(port);
|
|
break;
|
|
}
|
|
if (config != null) {
|
|
config.FixedRanges = fixedRanges;
|
|
}
|
|
return config;
|
|
}
|
|
|
|
internal PciConfig(String[] ids, PciPort port)
|
|
{
|
|
this.port = port;
|
|
this.Read();
|
|
this.Ids = ids;
|
|
}
|
|
|
|
public PciConfig(PciPort port)
|
|
{
|
|
this.port = port;
|
|
}
|
|
|
|
public ushort AddressPort
|
|
{
|
|
get { return port.addressPort.Port; }
|
|
}
|
|
|
|
public ushort DataPort
|
|
{
|
|
get { return port.dataPort.Port; }
|
|
}
|
|
|
|
public ushort Identifier
|
|
{
|
|
get { return port.identifier; }
|
|
}
|
|
|
|
public IoIrqRange GetIrq()
|
|
{
|
|
return new IoIrqRange(InterruptLine, 1);
|
|
}
|
|
|
|
public void SetInterrupt(byte irq)
|
|
{
|
|
Write8(PCI_INTERRUPT_LINE, irq);
|
|
}
|
|
|
|
public byte InterruptLine
|
|
{
|
|
get { return Read8(PCI_INTERRUPT_LINE); }
|
|
}
|
|
|
|
public void EnableIoSpace(bool Enable)
|
|
{
|
|
uint control = Read32(0x04);
|
|
uint send = (control | PCI_ENABLE_IO_SPACE) & 0xffff;
|
|
Write32(0x04, send);
|
|
}
|
|
|
|
public uint Read32(int offset) {
|
|
return port.Read32(offset);
|
|
}
|
|
|
|
public void Write32(int offset, uint value) {
|
|
port.Write32(offset, value);
|
|
}
|
|
|
|
protected ushort Read16(uint offset) {
|
|
return port.Read16(offset);
|
|
}
|
|
|
|
protected void Write16(int offset, ushort value) {
|
|
port.Write16(offset, value);
|
|
}
|
|
|
|
public byte Read8(int offset) {
|
|
return port.Read8(offset);
|
|
}
|
|
|
|
protected void Write8(int offset, byte value) {
|
|
port.Write8(offset, value);
|
|
}
|
|
|
|
protected virtual void Read()
|
|
{
|
|
uint u;
|
|
|
|
u = Read32(0x00);
|
|
VendorId = (ushort)(u & 0xffff);
|
|
DeviceId = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = Read32(0x04);
|
|
Control = (ushort)(u & 0xffff);
|
|
Status = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = Read32(0x08);
|
|
RevisionId = (byte)(u & 0xff);
|
|
Interface = (byte)((u >> 8) & 0xff);
|
|
SubClassId = (byte)((u >> 16) & 0xff);
|
|
ClassId = (byte)((u >> 24) & 0xff);
|
|
|
|
u = Read32(0x0c);
|
|
CacheLineSize = (byte)(u & 0xff);
|
|
LatencyTimer = (byte)((u >> 8) & 0xff);
|
|
HeaderType = (byte)((u >> 16) & 0xff);
|
|
BIST = (byte)((u >> 24) & 0xff);
|
|
|
|
this.Ids = GetIds();
|
|
|
|
#if VERBOSE || DEBUG_PCI
|
|
foreach (string id in Ids)
|
|
{
|
|
Tracing.Log(Tracing.Debug, "DeviceId: " + id);
|
|
}
|
|
// Tracing.Log(Tracing.Debug, "Read: {0}", Id);
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Builds the list of device IDs for this PCI device. We generate the same
|
|
/// strings that Windows uses for its hardware IDs and compatible IDs.
|
|
/// The order is significant; the PNP manager will search the device IDs,
|
|
/// one by one, for a device driver that matches. The list is ordered from
|
|
/// most specific to least specific.
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// WDM "hardware IDs":
|
|
/// PCI\VEN_xxxy&DEV_yyyy&SUBSYS_zzzzzzzz&REV_rr
|
|
/// PCI\VEN_xxxy&DEV_yyyy&SUBSYS_zzzzzzzz
|
|
/// PCI\VEN_xxxy&DEV_yyyy&CC_ccssii
|
|
/// PCI\VEN_xxxy&DEV_yyyy&CC_ccss
|
|
/// PCI\VEN_xxxy
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// WDM "compatible IDs":
|
|
/// PCI\VEN_xxxy&DEV_yyyy&REV_rr
|
|
/// PCI\VEN_xxxy&DEV_yyyy
|
|
/// PCI\VEN_xxxx&CC_ccssii
|
|
/// PCI\VEN_xxxx&CC_ccss
|
|
/// PCI\CC_ccssii
|
|
/// PCI\CC_ccss
|
|
/// </para>
|
|
/// </summary>
|
|
/// <returns>
|
|
/// An array containing the device IDs. The list is ordered from most specific
|
|
/// to least specific.
|
|
/// </returns>
|
|
public string[] GetIds()
|
|
{
|
|
const string pci_prefix = @"PCI/";
|
|
const string and = "&";
|
|
|
|
string id_classcode = "CC_" + ByteToHex(this.ClassId) + ByteToHex(this.SubClassId);
|
|
string id_classcode_interface = id_classcode + ByteToHex(this.Interface);
|
|
string id_vendor = "VEN_" + UInt16ToHex(this.VendorId);
|
|
string id_device = "DEV_" + UInt16ToHex(this.DeviceId);
|
|
string id_vendor_device = id_vendor + and + id_device;
|
|
string id_revision = "REV_" + ByteToHex(this.RevisionId);
|
|
string id_subsys = "SUBSYS_" + UInt16ToHex(this.SubsystemVendorId) + UInt16ToHex(this.SubsystemDeviceId);
|
|
|
|
#if ENABLE_OLD_SIGNATURE
|
|
string sing_id = String.Format("/pci/{0,2:x2}/{1,2:x2}/{2,4:x4}/{3,4:x4}/" +
|
|
"{4,2:x2}",
|
|
ClassId,
|
|
SubClassId,
|
|
VendorId,
|
|
DeviceId,
|
|
RevisionId);
|
|
#endif
|
|
|
|
string[] ids = {
|
|
#if ENABLE_OLD_SIGNATURE
|
|
sing_id,
|
|
#endif
|
|
|
|
// Hardware IDs
|
|
pci_prefix + id_vendor_device + and + id_subsys + and + id_revision,
|
|
pci_prefix + id_vendor_device + and + id_subsys,
|
|
pci_prefix + id_vendor_device + and + id_classcode_interface,
|
|
pci_prefix + id_vendor_device + and + id_classcode,
|
|
pci_prefix + id_vendor,
|
|
|
|
// Compatible IDs
|
|
pci_prefix + id_vendor_device + and + id_revision,
|
|
pci_prefix + id_vendor_device,
|
|
pci_prefix + id_vendor + and + id_classcode_interface,
|
|
pci_prefix + id_vendor + and + id_classcode,
|
|
pci_prefix + id_classcode_interface,
|
|
pci_prefix + id_classcode,
|
|
};
|
|
|
|
for (int i = 0; i < ids.Length; i++)
|
|
{
|
|
string id = ids[i];
|
|
id = id.Replace('\\', '/').ToLower();
|
|
ids[i] = id;
|
|
}
|
|
|
|
return ids;
|
|
}
|
|
|
|
static string ByteToHex(byte value)
|
|
{
|
|
StringBuilder sb = new StringBuilder(2);
|
|
sb.Append(HexDigits[value >> 4]);
|
|
sb.Append(HexDigits[value & 0xf]);
|
|
return sb.ToString();
|
|
}
|
|
|
|
static string UInt16ToHex(ushort value)
|
|
{
|
|
StringBuilder sb = new StringBuilder(4);
|
|
sb.Append(HexDigits[(value >> 12) & 0xf]);
|
|
sb.Append(HexDigits[(value >> 8) & 0xf]);
|
|
sb.Append(HexDigits[(value >> 4) & 0xf]);
|
|
sb.Append(HexDigits[value & 0xf]);
|
|
return sb.ToString();
|
|
|
|
}
|
|
|
|
const string HexDigits = "0123456789ABCDEF";
|
|
|
|
protected void ReadBaseAddresses(int n)
|
|
{
|
|
if (Read8(PCI_INTERRUPT_PIN) != 0)
|
|
{
|
|
// Add interrupt resource to list of ranges if present
|
|
DynamicRanges = new IoRange [n + 1];
|
|
DynamicRanges[n] = new IoIrqRange(Read8(PCI_INTERRUPT_LINE), 1);
|
|
}
|
|
else
|
|
{
|
|
DynamicRanges = new IoRange [n];
|
|
}
|
|
|
|
BaseAddresses = new uint [n];
|
|
BaseAddrSizes = new uint [n];
|
|
|
|
#if VERBOSE
|
|
Tracing.Log(Tracing.Debug, "ReadBaseAddresses()");
|
|
#endif
|
|
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "InterruptsDisabled: {0}", Processor.InterruptsDisabled());
|
|
for (int i = 0; i < n; i++) {
|
|
uint value = Read32(0x10 + i * 4);
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] -: {2:x8}", n, i, value);
|
|
}
|
|
#endif
|
|
|
|
uint control = Read32(0x04);
|
|
uint send = (control & (~(PCI_ENABLE_IO_SPACE|PCI_ENABLE_MEMORY_SPACE)))
|
|
& 0xffff;
|
|
if (control == 0x02b00003) {
|
|
send = (control & (~(PCI_ENABLE_IO_SPACE))) & 0xffff;
|
|
}
|
|
|
|
#if DONT_SKIP_NVIDIA
|
|
if (control == 0x02b00003) {
|
|
send = control & 0xffff;
|
|
|
|
send &= ~PCI_ENABLE_IO_SPACE;
|
|
port.Write32(0x04, send);
|
|
Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: ctrl={1:x8} send={2:x8}", n, control, send);
|
|
uint x = Read32(0x04);
|
|
Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: finl={1:x8}", n, x);
|
|
|
|
port.Write32(0x04, control & 0xffff);
|
|
x = Read32(0x04);
|
|
Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: last={1:x8}", n, x);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
port.Write32(0x04, send);
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}]: ctrl={1:x8} send={2:x8}",
|
|
n, control, send);
|
|
#endif
|
|
#if DEBUG_PCI
|
|
uint x = Read32(0x04);
|
|
Tracing.Log(Tracing.Debug, "Read[{0}]: finl={1:x8}", n, x);
|
|
#endif
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] A:", n, i);
|
|
#endif
|
|
uint addr = Read32(0x10 + i * 4);
|
|
uint size = 0;
|
|
|
|
// Find the size of the address space by moving to hi memory.
|
|
|
|
if ((addr & PCI_ADDRESS_IO_SPACE) != 0) {
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] B: {2:x8} ~0", n, i, addr);
|
|
#endif
|
|
port.Write32(0x10 + i * 4, ~0u);
|
|
size = Read32(0x10 + i * 4);
|
|
port.Write32(0x10 + i * 4, addr);
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] C: {2:x8}", n, i, size);
|
|
#endif
|
|
|
|
size &= ~0x3u;
|
|
size |= 0xffff0000;
|
|
}
|
|
else {
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] B: {2:x8} ~0", n, i, addr);
|
|
#endif
|
|
port.Write32(0x10 + i * 4, ~0xfu);
|
|
size = Read32(0x10 + i * 4);
|
|
port.Write32(0x10 + i * 4, addr);
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] C: {2:x8}", n, i, size);
|
|
#endif
|
|
|
|
size &= ~0xfu;
|
|
}
|
|
size = ~size + 1;
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}][{1}] D: {2:x8}", n, i, size);
|
|
#endif
|
|
|
|
if (size >= 2) {
|
|
if ((addr & PCI_ADDRESS_IO_SPACE) != 0) {
|
|
DynamicRanges[i] = new IoPortRange((ushort)(addr & ~0xf),
|
|
(ushort)size, Access.ReadWrite);
|
|
}
|
|
else {
|
|
DynamicRanges[i] = new IoMemoryRange((uint)(addr & ~0xf),
|
|
size, Access.ReadWrite);
|
|
}
|
|
BaseAddresses[i] = addr;
|
|
BaseAddrSizes[i] = size;
|
|
}
|
|
}
|
|
port.Write32(0x04, control & 0xffff);
|
|
#if DEBUG_PCI
|
|
Tracing.Log(Tracing.Debug, "Read[{0}]: done", n);
|
|
#endif
|
|
|
|
string s = "::";
|
|
for (int i = 0; i < DynamicRanges.Length; i++) {
|
|
if (DynamicRanges[i] != null) {
|
|
s += String.Format("A{0}={1} ", i, DynamicRanges[i]);
|
|
}
|
|
}
|
|
Tracing.Log(Tracing.Debug, "PCI {0}", s);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return String.Format("[PCI: VEN_{0:x4} DEV_{1:x4} CLASS {2:x2}.{3:x2}.{4:x2} BASE {5:x8}]",
|
|
this.VendorId,
|
|
this.DeviceId,
|
|
this.ClassId,
|
|
this.SubClassId,
|
|
this.Interface,
|
|
this.Base);
|
|
}
|
|
|
|
public override string ToPrint()
|
|
{
|
|
StringBuilder text = new StringBuilder();
|
|
base.DumpRanges(text);
|
|
text.AppendFormat(" PCI Vendor/Device: {0:x4}.{1:x4} rev {2:x2} {3} {4}\n",
|
|
this.VendorId,
|
|
this.DeviceId,
|
|
this.RevisionId,
|
|
this.Vendor,
|
|
this.Device);
|
|
text.AppendFormat(" PCI Class/Subclass: {0:x2}.{1:x2}.{2:x2}\n",
|
|
this.ClassId,
|
|
this.SubClassId,
|
|
this.Interface,
|
|
this.Class);
|
|
return text.ToString();
|
|
}
|
|
|
|
protected string PrintAddresses()
|
|
{
|
|
String s;
|
|
|
|
bool print = false;
|
|
for (int i = 0; i < BaseAddresses.Length; i++) {
|
|
if (BaseAddresses[i] != 0 || BaseAddrSizes[i] != 0) {
|
|
print = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!print &&
|
|
ROMBaseAddress == 0 && InterruptLine == 0 && InterruptPin == 0) {
|
|
|
|
return "";
|
|
}
|
|
|
|
s = String.Format(" RM={0:x8} IL={1,2:x2} IP={2,2:x2} ",
|
|
ROMBaseAddress,
|
|
InterruptLine,
|
|
InterruptPin);
|
|
|
|
int printed = 0;
|
|
for (int i = 0; i < BaseAddresses.Length; i++) {
|
|
if (DynamicRanges[i] != null) {
|
|
s += String.Format("A{0}={1} ", i, DynamicRanges[i]);
|
|
}
|
|
|
|
#if DONT_PRINT_RAW_ADDRESSS_BUT_ONLY_RANGES
|
|
if (BaseAddresses[i] == 0 && BaseAddrSizes[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
if ((BaseAddresses[i] & PCI_ADDRESS_IO_SPACE) != 0) {
|
|
s += String.Format("A{0}=IO:{1:x8}[{2:x}] ",
|
|
i, BaseAddresses[i], BaseAddrSizes[i]);
|
|
}
|
|
else {
|
|
if ((BaseAddresses[i] & PCI_TYPE_64BIT) != 0) {
|
|
s += String.Format("A{0}=64:{1:x8}[{2:x}] ",
|
|
i, BaseAddresses[i], BaseAddrSizes[i]);
|
|
}
|
|
else if ((BaseAddresses[i] & PCI_TYPE_20BIT) != 0) {
|
|
s += String.Format("A{0}=20:{1:x8}[{2:x}] ",
|
|
i, BaseAddresses[i], BaseAddrSizes[i]);
|
|
}
|
|
else {
|
|
s += String.Format("A{0}=32:{1:x8}[{2:x}] ",
|
|
i, BaseAddresses[i], BaseAddrSizes[i]);
|
|
}
|
|
}
|
|
#endif
|
|
printed++;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
protected string Vendor {
|
|
get {
|
|
switch (VendorId) {
|
|
case 0x1011:
|
|
return "DEC";
|
|
case 0x104c:
|
|
return "TI";
|
|
case 0x5333:
|
|
return "S3";
|
|
case 0x8086:
|
|
return "Intel";
|
|
case 0x10de:
|
|
return "nVidia";
|
|
case 0x1106:
|
|
return "VIA Technologies";
|
|
default:
|
|
return String.Format("{0,4:x4}", VendorId);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected string Device {
|
|
get {
|
|
switch (VendorId) {
|
|
case 0x8086:
|
|
switch (DeviceId) {
|
|
case 0x0484: return "82379AB";
|
|
case 0x1229: return "82559nic";
|
|
case 0x122E: return "82371FB";
|
|
case 0x1234: return "82371MX";
|
|
case 0x2410: return "82801AA";
|
|
case 0x7000: return "82371SB";
|
|
case 0x7110: return "82371AB";
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0x10de:
|
|
// NVIDIA
|
|
switch (DeviceId)
|
|
{
|
|
case 0x0050: return "PCI-to-ISA bridge";
|
|
case 0x0052: return "nForce PCI System Management Module";
|
|
case 0x0057: return "nForce Network Interface";
|
|
case 0x0059: return "Realtek AC'97 Audio";
|
|
case 0x005a: return "USB OHCI";
|
|
case 0x005d: return "PCI-to-PCI bridge";
|
|
case 0x005e: return "nForce4 HyperTransport Bridge";
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0x1106:
|
|
// VIA
|
|
switch (DeviceId)
|
|
{
|
|
case 0x3044: return "OHCI Compliant IEEE 1394 Host Controller";
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return String.Format("{0,4:x4}", DeviceId);
|
|
|
|
}
|
|
}
|
|
|
|
protected string Class {
|
|
get {
|
|
switch (ClassId) {
|
|
case PCI_CLASS_STORAGE:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_STORAGE_SCSI: return "Scsi";
|
|
case PCI_CLASS_STORAGE_IDE: return "Ide";
|
|
case PCI_CLASS_STORAGE_FLOPPY: return "Floppy";
|
|
case PCI_CLASS_STORAGE_IPI: return "Ipi";
|
|
case PCI_CLASS_STORAGE_RAID: return "Raid";
|
|
case PCI_CLASS_STORAGE_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_NETWORK:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet";
|
|
case PCI_CLASS_NETWORK_RING: return "Ring";
|
|
case PCI_CLASS_NETWORK_FDDI: return "Fddi";
|
|
case PCI_CLASS_NETWORK_ATM: return "Atm";
|
|
case PCI_CLASS_NETWORK_OTHER: return "Other";
|
|
case PCI_CLASS_NETWORK_FIP: return "FIP";
|
|
case PCI_CLASS_NETWORK_PICMG: return "PICMG";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_DISPLAY:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_DISPLAY_VGA: return "Vga";
|
|
case PCI_CLASS_DISPLAY_XGA: return "Xga";
|
|
case PCI_CLASS_DISPLAY_3D: return "3D";
|
|
case PCI_CLASS_DISPLAY_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_MULTIMEDIA:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_MULTIMEDIA_VIDEO: return "Video";
|
|
case PCI_CLASS_MULTIMEDIA_AUDIO: return "Audio";
|
|
case PCI_CLASS_MULTIMEDIA_TELEPHONY: return "Telephony";
|
|
case PCI_CLASS_MULTIMEDIA_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_MEMORY:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_MEMORY_RAM: return "Ram";
|
|
case PCI_CLASS_MEMORY_FLASH: return "Flash";
|
|
case PCI_CLASS_MEMORY_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_BRIDGE:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_BRIDGE_HOST: return "Host";
|
|
case PCI_CLASS_BRIDGE_ISA: return "Isa";
|
|
case PCI_CLASS_BRIDGE_EISA: return "Eisa";
|
|
case PCI_CLASS_BRIDGE_MC: return "Mc";
|
|
case PCI_CLASS_BRIDGE_PCI: return "Pci";
|
|
case PCI_CLASS_BRIDGE_PCMCIA: return "Pcmcia";
|
|
case PCI_CLASS_BRIDGE_NUBUS: return "Nubus";
|
|
case PCI_CLASS_BRIDGE_CARDBUS: return "Cardbus";
|
|
case PCI_CLASS_BRIDGE_RACEWAY: return "Raceway";
|
|
case PCI_CLASS_BRIDGE_SEMIPCI: return "Semipci";
|
|
case PCI_CLASS_BRIDGE_INFINIBAND: return "Infiniband";
|
|
case PCI_CLASS_BRIDGE_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_COMMUNICATION:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial";
|
|
case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel";
|
|
case PCI_CLASS_COMMUNICATION_MULTIPORT: return "Multiport";
|
|
case PCI_CLASS_COMMUNICATION_MODEM: return "Modem";
|
|
case PCI_CLASS_COMMUNICATION_GPIB: return "Gpib";
|
|
case PCI_CLASS_COMMUNICATION_SMARTCARD: return "Smartcard";
|
|
case PCI_CLASS_COMMUNICATION_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_SYSTEM:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_SYSTEM_PIC: return "Pic";
|
|
case PCI_CLASS_SYSTEM_DMA: return "Dma";
|
|
case PCI_CLASS_SYSTEM_TIMER: return "Timer";
|
|
case PCI_CLASS_SYSTEM_RTC: return "Rtc";
|
|
case PCI_CLASS_SYSTEM_PCIHP: return "Pcihp";
|
|
case PCI_CLASS_SYSTEM_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_INPUT:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard";
|
|
case PCI_CLASS_INPUT_PEN: return "Pen";
|
|
case PCI_CLASS_INPUT_MOUSE: return "Mouse";
|
|
case PCI_CLASS_INPUT_SCANNER: return "Scanner";
|
|
case PCI_CLASS_INPUT_GAMEPORT: return "Gameport";
|
|
case PCI_CLASS_INPUT_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_SERIAL:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_SERIAL_FIREWIRE: return "Firewire";
|
|
case PCI_CLASS_SERIAL_ACCESS: return "Access";
|
|
case PCI_CLASS_SERIAL_SSA: return "Ssa";
|
|
case PCI_CLASS_SERIAL_USB:
|
|
switch (this.Interface)
|
|
{
|
|
case 0x00: return "USB1.1 UHCI";
|
|
case 0x10: return "USB1.1 OHCI";
|
|
case 0x20: return "USB2.0 EHCI";
|
|
default:
|
|
return "Usb";
|
|
}
|
|
case PCI_CLASS_SERIAL_FIBRE: return "Fibre";
|
|
case PCI_CLASS_SERIAL_SMBUS: return "Smbus";
|
|
case PCI_CLASS_SERIAL_INFINIBAND: return "Infiniband";
|
|
case PCI_CLASS_SERIAL_IPMI: return "Ipmi";
|
|
case PCI_CLASS_SERIAL_SERCOS: return "Sercos";
|
|
case PCI_CLASS_SERIAL_CANBUS: return "Canbus";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
case PCI_CLASS_WIRELESS:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_WIRELESS_IRDA: return "Irda";
|
|
case PCI_CLASS_WIRELESS_IR: return "Ir";
|
|
case PCI_CLASS_WIRELESS_RF: return "Rf";
|
|
case PCI_CLASS_WIRELESS_BLUETOOTH: return "Bluetooth";
|
|
case PCI_CLASS_WIRELESS_BROADBAND: return "Broadband";
|
|
case PCI_CLASS_WIRELESS_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_I2O:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_I2O_I2O: return "I2O";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_SATELLITE:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_SATELLITE_TV: return "Tv";
|
|
case PCI_CLASS_SATELLITE_AUDIO: return "Audio";
|
|
case PCI_CLASS_SATELLITE_VOICE: return "Voice";
|
|
case PCI_CLASS_SATELLITE_DATA: return "Data";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_ENCRYPTION:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_ENCRYPTION_NETWORK: return "Network";
|
|
case PCI_CLASS_ENCRYPTION_ENTERTAINMENT:return "Entertainment";
|
|
case PCI_CLASS_ENCRYPTION_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
|
|
case PCI_CLASS_ACQUISITION:
|
|
switch (SubClassId) {
|
|
case PCI_CLASS_ACQUISITION_DPIO: return "Dpio";
|
|
case PCI_CLASS_ACQUISITION_PERF: return "Perf";
|
|
case PCI_CLASS_ACQUISITION_COMM: return "Comm";
|
|
case PCI_CLASS_ACQUISITION_MGMT: return "Mgmt";
|
|
case PCI_CLASS_ACQUISITION_OTHER: return "Other";
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
default: return String.Format("{0,2:x2}", SubClassId);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected string Base {
|
|
get {
|
|
switch (ClassId) {
|
|
case PCI_CLASS_STORAGE: return "Storage";
|
|
case PCI_CLASS_NETWORK: return "Network";
|
|
case PCI_CLASS_DISPLAY: return "Display";
|
|
case PCI_CLASS_MULTIMEDIA: return "Multimedia";
|
|
case PCI_CLASS_MEMORY: return "Memory";
|
|
case PCI_CLASS_BRIDGE: return "Bridge";
|
|
case PCI_CLASS_COMMUNICATION: return "Communication";
|
|
case PCI_CLASS_SYSTEM: return "System";
|
|
case PCI_CLASS_INPUT: return "Input";
|
|
case PCI_CLASS_DOCKING: return "Docking";
|
|
case PCI_CLASS_PROCESSOR: return "Processor";
|
|
case PCI_CLASS_SERIAL: return "Serial";
|
|
case PCI_CLASS_OTHERS: return "Others";
|
|
case PCI_CLASS_WIRELESS: return "Wireless";
|
|
case PCI_CLASS_I2O: return "I2O";
|
|
case PCI_CLASS_SATELLITE: return "Satellite";
|
|
case PCI_CLASS_ENCRYPTION: return "Encryption";
|
|
case PCI_CLASS_ACQUISITION: return "Acquisition";
|
|
default: return String.Format("{0,2:x2}", ClassId);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool MemorySpaceEnabled
|
|
{
|
|
get { return (Control & PCI_ENABLE_MEMORY_SPACE) != 0; }
|
|
}
|
|
|
|
public bool IoSpaceEnabled
|
|
{
|
|
get { return (Control & PCI_ENABLE_IO_SPACE) != 0; }
|
|
}
|
|
|
|
public bool InterruptsEnabled
|
|
{
|
|
get { return (Control & PCI_DISABLE_INTERRUPTS) == 0; }
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciBridgeConfig : PciConfig
|
|
{
|
|
// Bridges: (HeaderType & ~PCI_MULTIFUNCTION) == PCI_BRIDGE_TYPE
|
|
// public uint BaseAddresses[2]; // 10..17
|
|
protected byte PrimaryBus; // 18..18
|
|
protected byte SecondaryBus; // 19..19
|
|
protected byte SubordinateBus; // 1a..1a
|
|
protected byte SecondaryLatency; // 1b..1b
|
|
protected byte IOBase; // 1c..1c
|
|
protected byte IOLimit; // 1d..1d
|
|
protected ushort SecondaryStatus; // 1e..1f
|
|
protected ushort MemoryBase; // 20..21
|
|
protected ushort MemoryLimit; // 22..23
|
|
protected ushort PrefetchBase; // 24..25
|
|
protected ushort PrefetchLimit; // 26..27
|
|
protected uint PrefetchBaseUpper32; // 28..2b
|
|
protected uint PrefetchLimitUpper32; // 2c..2f
|
|
protected ushort IOBaseUpper16; // 30..31
|
|
protected ushort IOLimitUpper16; // 32..33
|
|
// protected uint Reserved; // 34..37
|
|
// protected uint ROMBaseAddress; // 38..3b
|
|
#if DISABLED
|
|
// protected byte InterruptLine; // 3c..3c
|
|
#endif
|
|
// protected byte InterruptPin; // 3d..3d
|
|
protected ushort BridgeControl; // 3e..3f
|
|
|
|
public PciBridgeConfig(PciPort port)
|
|
: base(port)
|
|
{
|
|
Read();
|
|
}
|
|
|
|
protected override void Read()
|
|
{
|
|
base.Read();
|
|
base.ReadBaseAddresses(2);
|
|
|
|
uint u;
|
|
|
|
u = port.Read32(0x18);
|
|
PrimaryBus = (byte)(u & 0xff);
|
|
SecondaryBus = (byte)((u >> 8) & 0xff);
|
|
SubordinateBus = (byte)((u >> 16) & 0xff);
|
|
SecondaryLatency = (byte)((u >> 24) & 0xff);
|
|
|
|
u = port.Read32(0x1c);
|
|
IOBase = (byte)(u & 0xff);
|
|
IOLimit = (byte)((u >> 8) & 0xff);
|
|
SecondaryStatus = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = port.Read32(0x20);
|
|
MemoryBase = (ushort)(u & 0xffff);
|
|
MemoryLimit = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = port.Read32(0x24);
|
|
PrefetchBase = (ushort)(u & 0xffff);
|
|
PrefetchLimit = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = port.Read32(0x28);
|
|
PrefetchBaseUpper32 = u;
|
|
|
|
u = port.Read32(0x2c);
|
|
PrefetchLimitUpper32 = u;
|
|
|
|
u = port.Read32(0x30);
|
|
IOBaseUpper16 = (ushort)(u & 0xffff);
|
|
IOLimitUpper16 = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = port.Read32(0x38);
|
|
ROMBaseAddress = u;
|
|
|
|
u = port.Read32(0x3c);
|
|
#if DISABLED
|
|
InterruptLine = (byte)(u & 0xff);
|
|
#endif
|
|
InterruptPin = (byte)((u >> 8) & 0xff);
|
|
BridgeControl = (ushort)((u >> 16) & 0xffff);
|
|
}
|
|
|
|
public override string ToPrint()
|
|
{
|
|
return base.ToPrint() +
|
|
String.Format("BUS={0,2:x2}.{1,2:x2}.{2,2:x2} IO={3,4:x4}..{4,4:x4}",
|
|
PrimaryBus, SecondaryBus, SubordinateBus,
|
|
IOBase, IOLimit) +
|
|
"" +
|
|
base.PrintAddresses() + "";
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciDeviceConfig : PciConfig
|
|
{
|
|
// Devices: (HeaderType & ~PCI_MULTIFUNCTION) == PCI_DEVICE_TYPE
|
|
// public uint BaseAddresses[6]; // 10..27
|
|
protected uint CardbusCisPtr; // 28..2b
|
|
// protected ushort SubsystemVendorId; // 2c..2d
|
|
// protected ushort SubsystemDeviceId; // 2e..2f
|
|
// protected uint ROMBaseAddress; // 30..33
|
|
protected byte Capabilities; // 34..34
|
|
// protected byte Reserved[7]; // 35..38
|
|
#if DISABLED
|
|
// protected byte InterruptLine; // 3c..3c
|
|
#endif
|
|
// protected byte InterruptPin; // 3d..3d (ro)
|
|
protected byte MinimumGrant; // 3e..3e (ro)
|
|
protected byte MaximumLatency; // 3f..3f (ro)
|
|
|
|
public PciDeviceConfig(PciPort port)
|
|
: base(port)
|
|
{
|
|
Read();
|
|
}
|
|
|
|
protected override void Read()
|
|
{
|
|
base.Read();
|
|
base.ReadBaseAddresses(6);
|
|
|
|
uint u;
|
|
|
|
u = port.Read32(0x28);
|
|
CardbusCisPtr = u;
|
|
|
|
u = port.Read32(0x2c);
|
|
SubsystemVendorId = (ushort)(u & 0xffff);
|
|
SubsystemDeviceId = (ushort)((u >> 16) & 0xffff);
|
|
|
|
u = port.Read32(0x30);
|
|
ROMBaseAddress = u;
|
|
|
|
u = port.Read32(0x34);
|
|
Capabilities = (byte)(u & 0xff);
|
|
|
|
u = port.Read32(0x3c);
|
|
if ((u & 0xff) == 0) {
|
|
port.Write32(0x3c, u | 0x7);
|
|
u = port.Read32(0x3c);
|
|
}
|
|
|
|
#if DISABLED
|
|
InterruptLine = (byte)(u & 0xff);
|
|
#endif
|
|
InterruptPin = (byte)((u >> 8) & 0xff);
|
|
MinimumGrant = (byte)((u >> 16) & 0xff);
|
|
MaximumLatency = (byte)((u >> 24) & 0xff);
|
|
|
|
Ids = GetIds();
|
|
}
|
|
|
|
public override string ToPrint()
|
|
{
|
|
String s = base.ToPrint() + "\n " + base.PrintAddresses();
|
|
|
|
if (CardbusCisPtr != 0 ||
|
|
Capabilities != 0 ||
|
|
MinimumGrant != 0 ||
|
|
MaximumLatency != 0) {
|
|
|
|
s += String.Format(" cis={0:x8} cap={1,2:x2} mg={2,2:x2} ml={3,2:x2}",
|
|
CardbusCisPtr,
|
|
Capabilities,
|
|
MinimumGrant,
|
|
MaximumLatency);
|
|
}
|
|
return s;
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciCardbusConfig : PciConfig
|
|
{
|
|
public PciCardbusConfig(PciPort port)
|
|
: base(port)
|
|
{
|
|
BaseAddresses = new uint [0];
|
|
Read();
|
|
}
|
|
|
|
protected override void Read()
|
|
{
|
|
base.Read();
|
|
}
|
|
|
|
public override string ToPrint()
|
|
{
|
|
return base.ToPrint();
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciPort
|
|
{
|
|
internal readonly IoPort addressPort;
|
|
internal readonly IoPort dataPort;
|
|
internal readonly ushort identifier;
|
|
|
|
public PciPort(IoPort addressPort, IoPort dataPort, ushort identifier)
|
|
{
|
|
this.addressPort = addressPort;
|
|
this.dataPort = dataPort;
|
|
this.identifier = identifier;
|
|
}
|
|
|
|
public ushort AddressPort
|
|
{
|
|
get { return addressPort.Port; }
|
|
}
|
|
|
|
public ushort DataPort
|
|
{
|
|
get { return dataPort.Port; }
|
|
}
|
|
|
|
public ushort Identifier
|
|
{
|
|
get { return identifier; }
|
|
}
|
|
|
|
public PciConfig ConfigForPort()
|
|
{
|
|
uint u = Read32(0);
|
|
|
|
switch (u & PciConfig.PCI_TYPE_MASK) {
|
|
case PciConfig.PCI_DEVICE_TYPE:
|
|
return new PciDeviceConfig(this);
|
|
case PciConfig.PCI_BRIDGE_TYPE:
|
|
return new PciBridgeConfig(this);
|
|
case PciConfig.PCI_CARDBUS_TYPE:
|
|
return new PciCardbusConfig(this);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public uint Read32(int offset)
|
|
{
|
|
#if !DONT_CHECK_IO_BOUNDS
|
|
if ((offset & 0x3) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
#endif
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
return dataPort.Read32();
|
|
}
|
|
|
|
public ushort Read16(uint offset)
|
|
{
|
|
#if !DONT_CHECK_IO_BOUNDS
|
|
if ((offset & 0x1) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
#endif
|
|
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
return dataPort.Read16(offset & 0x1);
|
|
}
|
|
|
|
public byte Read8(int offset)
|
|
{
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
addressPort.Write32(config);
|
|
return dataPort.Read8((uint)offset & 0x3);
|
|
}
|
|
|
|
public void Write32(int offset, uint value)
|
|
{
|
|
#if !DONT_CHECK_IO_BOUNDS
|
|
if ((offset & 0x3) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
#endif
|
|
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
dataPort.Write32(value);
|
|
}
|
|
|
|
public void Write16(int offset, ushort value)
|
|
{
|
|
#if !DONT_CHECK_IO_BOUNDS
|
|
if ((offset & 0x1) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
#endif
|
|
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
dataPort.Write16((uint)(offset & 0x1), value);
|
|
}
|
|
|
|
public void Write8(int offset, byte value)
|
|
{
|
|
uint config = (((uint)offset & 0xff) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
dataPort.Write8((uint)(offset & 0x3), value);
|
|
}
|
|
}
|
|
} // end namespace Microsoft.Singularity.Io
|