388 lines
13 KiB
ObjectPascal
388 lines
13 KiB
ObjectPascal
{ ************************************************
|
|
* Asuro
|
|
* Unit: Drivers/PCI
|
|
* Description: PCI Driver
|
|
************************************************
|
|
* Author: Aaron Hance
|
|
* Contributors:
|
|
************************************************ }
|
|
|
|
unit PCI;
|
|
|
|
interface
|
|
|
|
uses
|
|
util,
|
|
console;
|
|
|
|
type
|
|
|
|
TClass_Code = (
|
|
LEGACY, MASS_STORAGE_CONTROLLER, NETWORK_CONTROLLER,
|
|
DISPLAY_CONTROLLER, MULTIMEDIA_CONTROLLER, MEMORY_CONTROLLER,
|
|
BRIDGE_DEVICE, SIMPLE_COMM_CONTROLLER, BASE_SYS_PERIPHERALS,
|
|
INPUT_DEVICE, DOCKING_STATION, PROCESSOR, SERIAL_BUS_CONTROLLER,
|
|
WIRELESS_CONTROLLER, INTELLIGENT_IO_CONTROLLER,
|
|
SATELLITE_COMM_CONTROLLER, ENCRYPTION_CONTROLLER,
|
|
SIGNAL_PROCESSING_CONTROLLER, RESERVED
|
|
); // 0XFF = OTHER DEVICE
|
|
|
|
// TSub_Class_Codes = record // first half sub device, second half prog id
|
|
// any_non_vga_compatible : uint16 = $0000;
|
|
// any_vga_compatible : uint16 = $0100;
|
|
// scsi_bus_controller : uint16 = $0000;
|
|
// ide_controller : uint16 = $01FF;
|
|
// floppy_controller : uint16 = $0200;
|
|
// ipi_bus_controller : uint16 = $0300;
|
|
// raid_controller : uint16 = $0400;
|
|
// ata_single_dma : uint16 = $0520;
|
|
// ata_chained_dma : uint16 = $0530;
|
|
// serial_ata_ahci_vsi : uint16 = $0600;
|
|
// serial_ata_ahci : uint16 = $0601;
|
|
// serial_attached_scsi : uint16 = $0700;
|
|
// other_mass_storage : uint16 = $8000;
|
|
// ethernet_controller : uint16 = $0000;
|
|
// token_ring_controller : uint16 = $0100;
|
|
// fddi_controller : uint16 = $0200;
|
|
// atm_controller : uint16 = $0300;
|
|
// isdn_controller : uint16 = $0400;
|
|
// worldfip_controller : uint16 = $0500;
|
|
// picmg_multi_computing : uint16 = $0600;
|
|
// other_network_controller : uint16 = $8000;
|
|
// vga_compatible_controller : uint16 = $0000;
|
|
// c8512_compatible_controller : uint16 = $0001;
|
|
// xga_controller : uint16 = $0100;
|
|
// c3d_controller : uint16 = $0200;
|
|
// other_display_controller : uint16 = $8000;
|
|
// video_device : uint16 = $0000;
|
|
// audio_device : uint16 = $0100;
|
|
// computer_telephony_device : uint16 = $0200;
|
|
// other_multimedia_device : uint16 = $8000;
|
|
// ram_controller : uint16 = $0000;
|
|
// flash_controller : uint16 = $0100;
|
|
// other_memory_controller : uint16 = $8000;
|
|
// host_bridge : uint16 = $0100;
|
|
// isa_bridge : uint16 = $0200;
|
|
// eisa_bridge : uint16 = $0300;
|
|
// pci_2_pci_bridge : uint16 = $0400;
|
|
// subtractive_pci_2_pci_bridge : uint16 = $0401;
|
|
// pcmcia_bridge : uint16 = $0500;
|
|
// nubus_bridge : uint16 = $0600;
|
|
// cardbus_bridge : uint16 = $0700;
|
|
// raceway_bridge : uint16 = $0800;
|
|
// semi_pci_2_pci_bridge_p : uint16 = $0940;
|
|
// semi_pci_2_pci_bridge_s : uint16 = $0980;
|
|
// infiniband_2_pci_bridge : uint16 = $0A00;
|
|
// other_bridge_device : uint16 = $8000;
|
|
// end;
|
|
|
|
TPCI_Config = bitpacked record
|
|
enable_bit : boolean;
|
|
reserved : ubit7;
|
|
bus_number : uint8;
|
|
device_number : ubit5;
|
|
function_number : ubit3;
|
|
register_offset : ubit6;
|
|
always_0 : ubit2;
|
|
end;
|
|
|
|
TPCI_BIST = bitpacked record
|
|
capable : boolean;
|
|
start : boolean;
|
|
reserved : ubit2;
|
|
completion_code : ubit3;
|
|
end;
|
|
|
|
TPCI_Header_Type = bitpacked record
|
|
always_0 : boolean;
|
|
MF : boolean;
|
|
header_type : ubit7;
|
|
end;
|
|
|
|
TPCI_Memory_BAR = bitpacked record
|
|
address : ubit28; //16-Byte aligned
|
|
prefetchable : boolean;
|
|
bar_type : ubit2;
|
|
always_0 : boolean;
|
|
end;
|
|
|
|
TPCI_IO_BAR = bitpacked record
|
|
address : ubit30; //4-byte aligned
|
|
reserved : boolean;
|
|
always_0 : boolean;
|
|
end;
|
|
|
|
TPCI_Device = packed record
|
|
device_id : uint16;
|
|
vendor_id : uint16;
|
|
status : uint16;
|
|
command : uint16;
|
|
class_code : uint8;
|
|
subclass_class : uint8;
|
|
prog_if : uint8;
|
|
revision_id : uint8;
|
|
BIST : uint8;
|
|
header_type : uint8;
|
|
latency_timer : uint8;
|
|
cache_size : uint8;
|
|
address0 : uint32;
|
|
address1 : uint32;
|
|
address2 : uint32;
|
|
address3 : uint32;
|
|
address4 : uint32;
|
|
address5 : uint32;
|
|
CIS_pointer : uint32;
|
|
subsystem_id : uint16;
|
|
subsystem_vid : uint16;
|
|
exp_rom_addr : uint32;
|
|
reserved0 : uint16;
|
|
reserved1 : uint8;
|
|
capabilities : uint8;
|
|
reserved2 : uint32;
|
|
max_latency : uint8;
|
|
min_grant : uint8;
|
|
interrupt_pin : uint8;
|
|
interrupt_line : uint8;
|
|
end;
|
|
|
|
TPCI_Device_Bridge = bitpacked record
|
|
placeholder : uint8;
|
|
end;
|
|
|
|
TCommand_Register = bitpacked record
|
|
reserved : ubit5;
|
|
interupt_disable : boolean;
|
|
fast_b2b_enable : boolean;
|
|
seer_enable : boolean;
|
|
reserved0 : boolean;
|
|
parity_err_response : boolean;
|
|
VGA_palette_snoop : boolean;
|
|
mem_wai_enable : boolean;
|
|
special_cycles : boolean;
|
|
bus_master : boolean;
|
|
memory_space : boolean;
|
|
io_space : boolean;
|
|
end;
|
|
|
|
TStatus_Register = bitpacked record
|
|
detected_parity_error,
|
|
signaled_sys_error,
|
|
received_master_abort,
|
|
received_target_abort,
|
|
signaled_target_abort : boolean;
|
|
DEVSEL_timing : ubit2;
|
|
master_data_parity_error,
|
|
fast_b2b_capable,
|
|
reserved,
|
|
c66Mhz_compatible,
|
|
capabilities_list,
|
|
interrupt_status : boolean;
|
|
reserved0 : ubit2;
|
|
end;
|
|
|
|
var
|
|
devices : array[0..8191] of TPCI_Device;
|
|
busses : array[0..256] of TPCI_Device_Bridge;
|
|
|
|
device_count : uint16 = 0;
|
|
bus_count : uint16 = 0;
|
|
|
|
procedure init();
|
|
procedure loadConfig(bus : uint8; slot : uint8; func : uint8; offset : uint8);
|
|
function check_device(bus : uint8; device : uint8) : boolean;
|
|
|
|
function get_vendor_ID(bus : uint8; slot : uint8; func : uint8; offset : uint8) : uint16;
|
|
function isDevice(bus : uint8; slot : uint8; func : uint8; offset : uint8) : ubit2;
|
|
|
|
function read8(bus : uint8; slot : uint8; func : uint8; offset : uint8; part : uint8) : uint8;
|
|
function read16(bus : uint8; slot : uint8; func : uint8; offset : uint8; part : uint8) : uint16;
|
|
function read32(bus : uint8; slot : uint8; func : uint8; offset : uint8) : uint32;
|
|
|
|
function read_device_config(bus : uint8; slot : uint8; func : uint8; offset : uint8) : TPCI_Device;
|
|
//function read_bridge_config() : TPCI_Device_Bridge;
|
|
|
|
implementation
|
|
|
|
procedure init();
|
|
var
|
|
i : uint16;
|
|
begin
|
|
//enumerate master pci bus devices
|
|
for i:=0 to 31 do begin
|
|
check_device(0, i);
|
|
end;
|
|
|
|
//TODO while there are unchecked nested busses, check nested busses
|
|
end;
|
|
|
|
procedure loadConfig(bus : uint8; slot : uint8; func : uint8; offset : uint8);
|
|
var
|
|
packet : TPCI_Config;
|
|
packetI : uint32;
|
|
begin
|
|
// packet.enable_bit := true;
|
|
// packet.bus_number := bus;
|
|
// packet.device_number := slot;
|
|
// packet.function_number := func;
|
|
// packet.register_offset := offset;
|
|
// packet.always_0 := $0;
|
|
|
|
packetI := ($1 shl 31);
|
|
packetI := packetI or (bus shl 16);
|
|
packetI := packetI or (slot shl 11);
|
|
packetI := packetI or (func shl 8);
|
|
packetI := packetI or (offset shl 2);
|
|
|
|
outl($CF8, uint32(packetI));
|
|
end;
|
|
|
|
function check_device(bus : uint8; device : uint8) : boolean;
|
|
var
|
|
vendor_id : uint16;
|
|
isDeviceb : uint8;
|
|
begin
|
|
|
|
vendor_id := get_vendor_ID(bus, device, 0, 0);
|
|
if vendor_id = $FFFF then exit;
|
|
|
|
isDeviceb := isDevice(bus, device, 0, 8);
|
|
if isDeviceb = 1 then begin
|
|
devices[device_count] := read_device_config(bus, device, 0, 0);
|
|
device_count := device_count + 1;
|
|
check_device := true;
|
|
end else begin
|
|
console.writestringln('NESTED BUS FOUND');
|
|
//busses[bus_count] := read_bridge_config();
|
|
bus_count := bus_count + 1;
|
|
check_device := false;
|
|
end;
|
|
end;
|
|
|
|
function get_vendor_ID(bus : uint8; slot : uint8; func : uint8; offset : uint8) : uint16;
|
|
begin
|
|
get_vendor_ID := read16(bus, slot, func, offset, 0);
|
|
end;
|
|
|
|
function isDevice(bus : uint8; slot : uint8; func : uint8; offset : uint8) : ubit2;
|
|
begin
|
|
if(read8(bus, slot, func, offset, 2) = $06) then begin
|
|
isDevice := 0;
|
|
exit;
|
|
end;
|
|
|
|
isDevice := 1;
|
|
end;
|
|
|
|
function read8(bus : uint8; slot : uint8; func : uint8; offset : uint8; part : uint8) : uint8;
|
|
begin
|
|
loadConfig(bus, slot, func, offset);
|
|
read8 := (inl($CFC) shr (part * 8)) and $FF;
|
|
end;
|
|
|
|
function read16(bus : uint8; slot : uint8; func : uint8; offset : uint8; part : uint8) : uint16;
|
|
begin
|
|
loadConfig(bus, slot, func, offset);
|
|
read16 := (inl($CFC) shr (part * 16)) and $FFFF;
|
|
end;
|
|
|
|
function read32(bus : uint8; slot : uint8; func : uint8; offset : uint8) : uint32;
|
|
begin
|
|
loadConfig(bus, slot, func, offset);
|
|
read32 := inl($CFC);
|
|
end;
|
|
|
|
function read_device_config(bus : uint8; slot : uint8; func : uint8; offset : uint8) : TPCI_Device;
|
|
var
|
|
tmp : TPCI_Device;
|
|
i : uint16;
|
|
off : uint32;
|
|
|
|
begin
|
|
memset(uint32(@tmp), 0, sizeof(TPCI_Device));
|
|
|
|
// for i:=0 to 16 do begin
|
|
// console.writehexln(read32(0, slot, 0, offset + i, 0));
|
|
// psleep(1000);
|
|
// end;
|
|
|
|
off:= offset;
|
|
tmp.device_id := read16(bus, slot, func, off, 1);
|
|
tmp.vendor_id := read16(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.status := read16(bus, slot, func, off, 1);
|
|
tmp.command := read16(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.class_code := read8(bus, slot, func, off, 3);
|
|
tmp.subclass_class := read8(bus, slot, func, off, 2);
|
|
tmp.prog_if := read8(bus, slot, func, off, 1);
|
|
tmp.revision_id := read8(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.BIST := read8(bus, slot, func, off, 3);
|
|
tmp.header_type := read8(bus, slot, func, off, 2);
|
|
tmp.latency_timer := read8(bus, slot, func, off, 1);
|
|
tmp.cache_size := read8(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.address0 := read32(bus, slot, func, off);
|
|
off:= off+4;
|
|
tmp.address1 := read32(bus, slot, func, off);
|
|
off:= off+4;
|
|
tmp.address2 := read32(bus, slot, func, off);
|
|
off:= off+4;
|
|
tmp.address3 := read32(bus, slot, func, off);
|
|
off:= off+4;
|
|
tmp.address4 := read32(bus, slot, func, off);
|
|
off:= off+4;
|
|
tmp.address5 := read32(bus, slot, func, off);
|
|
|
|
off:= off+4;
|
|
tmp.CIS_pointer := read32(bus, slot, func, off);
|
|
|
|
off:= off+4;
|
|
tmp.subsystem_id := read16(bus, slot, func, off, 2);
|
|
tmp.subsystem_vid := read16(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.exp_rom_addr := read32(bus, slot, func, off);
|
|
|
|
off:= off+4;
|
|
tmp.reserved0 := read16(bus, slot, func, off, 3);
|
|
tmp.reserved1 := read8(bus, slot, func, off, 1);
|
|
tmp.capabilities := read8(bus, slot, func, off, 0);
|
|
|
|
off:= off+4;
|
|
tmp.reserved2 := read32(bus, slot, func, off);
|
|
|
|
off:= off+4;
|
|
tmp.max_latency := read8(bus, slot, func, off, 3);
|
|
tmp.min_grant := read8(bus, slot, func, off, 2);
|
|
tmp.interrupt_pin := read8(bus, slot, func, off, 1);
|
|
tmp.interrupt_line := read8(bus, slot, func, off, 0);
|
|
|
|
console.writestring('PCI: Found Device: ');
|
|
console.writehex(slot);
|
|
console.writestring(' ');
|
|
console.writehex(tmp.device_id);
|
|
console.writestring(' ');
|
|
console.writehex(tmp.vendor_id);
|
|
console.writestring(' ');
|
|
console.writehex(tmp.class_code);
|
|
console.writestring(' ');
|
|
console.writehexln(tmp.subclass_class);
|
|
|
|
//psleep(300);
|
|
|
|
read_device_config := tmp;
|
|
end;
|
|
|
|
// function read_bridge_config() : TPCI_Device_Bridge;
|
|
// begin
|
|
// read_bridge_config.placeholder = $FF;
|
|
// end;
|
|
|
|
end.
|
|
|