blob: c9c96c764c05cea077c6d1edae7dedb9cf1235f6 [file] [log] [blame] [raw]
"use strict";
var
/** @const */ PCI_VENDOR_ID = 0x00 /* 16 bits */
/** @const */ ,PCI_DEVICE_ID = 0x02 /* 16 bits */
/** @const */ ,PCI_COMMAND = 0x04 /* 16 bits */
/** @const */ ,PCI_BASE_ADDRESS_0 = 0x10 /* 32 bits */
/** @const */ ,PCI_BASE_ADDRESS_1 = 0x14 /* 32 bits [htype 0,1 only] */
/** @const */ ,PCI_BASE_ADDRESS_2 = 0x18 /* 32 bits [htype 0 only] */
/** @const */ ,PCI_BASE_ADDRESS_3 = 0x1c /* 32 bits */
/** @const */ ,PCI_BASE_ADDRESS_4 = 0x20 /* 32 bits */
/** @const */ ,PCI_BASE_ADDRESS_5 = 0x24 /* 32 bits */
/** @const */ ,PCI_INTERRUPT_LINE = 0x3c /* 8 bits */
/** @const */ ,PCI_CLASS_REVISION = 0x08; /* High 24 bits are class, low 8 revision */
/** @constructor */
function PCI(dev)
{
var
io = dev.io,
pci_data = 0,
pci_counter = 0,
pci_response = -1,
pci_status = -1,
self = this;
// TODO: Change the format of this
this.devices = {};
/*
io.register_write(0xCF9, function(value)
{
dbg_log("PCI reboot: " + h(value, 2), LOG_PCI);
// PCI reboot
if(value & 6)
{
cpu_restart();
}
});*/
io.register_read(0xCFC, function()
{
return pci_response & 0xFF;
});
io.register_read(0xCFD, function()
{
return pci_response >> 8 & 0xFF;
});
io.register_read(0xCFE, function()
{
return pci_response >> 16 & 0xFF;
});
io.register_read(0xCFF, function()
{
return pci_response >> 24 & 0xFF;
});
io.register_read(0xCF8, function()
{
return pci_status & 0xFF;
});
io.register_read(0xCF9, function()
{
return pci_status >> 8 & 0xFF;
});
io.register_read(0xCFA, function()
{
return pci_status >> 16 & 0xFF;
});
io.register_read(0xCFB, function()
{
return pci_status >> 24 & 0xFF;
});
io.register_write(0xCF8, function(out_byte)
{
pci_data = pci_data & ~0xFF | out_byte;
});
io.register_write(0xCF9, function(out_byte)
{
pci_data = pci_data & ~0xFF00 | out_byte << 8;
});
io.register_write(0xCFA, function(out_byte)
{
pci_data = pci_data & ~0xFF0000 | out_byte << 16;
});
io.register_write(0xCFB, function(out_byte)
{
pci_data = pci_data & 0xFFFFFF | out_byte << 24;
pci_query(pci_data);
});
function pci_query(dword)
{
var dbg_line = "PCI: ";
// Bit | .31 .0
// Fmt | EBBBBBBBBDDDDDFFFRRRRRR00
var bdf = (dword & 0x7FFFFFFF) >> 8,
addr = dword & 0xFC,
devfn = bdf & 0xFF,
bus = bdf >> 8,
dev = bdf >> 3 & 0x1F,
fn = bdf & 7,
enabled = dword >> 31 & 1;
dbg_line += " enabled=" + (enabled);
dbg_line += " bdf=" + h(bdf);
dbg_line += " addr=" + h(addr);
dbg_log(dbg_line + " " + h(dword >>> 0, 8), LOG_PCI);
if(dword === (0x80000000 | 0))
{
pci_status = 0x80000000;
}
else if(self.devices[bdf])
{
var device = self.devices[bdf];
pci_status = 0x80000000;
if(addr === PCI_VENDOR_ID)
{
pci_response = device.vendor_id;
}
else if(addr === PCI_CLASS_REVISION)
{
pci_response = device.class_revision;
}
else if(addr === PCI_BASE_ADDRESS_5)
{
pci_response = device.iobase;
}
else if(addr === PCI_INTERRUPT_LINE)
{
pci_response = device.irq;
}
else
{
dbg_log("unimplemented addr " + h(addr) + " for device " + h(bdf), LOG_PCI);
pci_response = 0;
}
}
else
{
pci_response = 0;
pci_status = 0;
}
}
this.register_device = function(device, device_id)
{
dbg_assert(!this.devices[device_id]);
this.devices[device_id] = device;
};
// ~% lspci -x
// 00:00.0 Host bridge: Intel Corporation 4 Series Chipset DRAM Controller (rev 02)
// 00: 86 80 20 2e 06 00 90 20 02 00 00 06 00 00 00 00
// 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 20: 00 00 00 00 00 00 00 00 00 00 00 00 43 10 d3 82
// 30: 00 00 00 00 e0 00 00 00 00 00 00 00 00 00 00 00
this.register_device({
irq: 0,
iobase: 0,
vendor_id: 0x8680202e,
class_revision: 0x06009020,
}, 0);
}