Octocontrabass, I am not 100 percent sure I am reading correctly. If you feel like it, you take a quick peek at my source code. The pci_config_read_word function is translated from the wiki page, but my offsets might be wrong.
Code: Select all
fn pci_config_read_dword(bus: u8, device: u8, function: u8, offset: u8) -> u32{
let long_bus = bus as u32;
let long_slot = device as u32;
let long_func = function as u32;
let mut tmp = 0u32;
//Create the address as per figure 1 at the link above.
let address = ((long_bus << 16) | (long_slot << 11)
| (long_func << 8) | (offset & 0xFC) as u32 | (0x80000000 as u32)) as u32;
//Port to be used for the address.
let mut port1:PortGeneric<u32, ReadWriteAccess> = Port::new(0xCF8);
unsafe {
//Write the address
port1.write(address);
}
//Port to be used for the data.
let mut port2: PortGeneric<u32, ReadWriteAccess> = Port::new(0xCFC);
unsafe { port2.read() }
}
^^ this is the function to read a dword from the configuration register. This might perhaps be a naive approach, I am not sure.
Code: Select all
///Read the header type of a pci device from its configuration space
fn get_pci_header_type(bus: u8, device: u8)->u8{
pci_config_read_word(bus, device, 0, 0xC+0x2).to_le_bytes()[1]
}
///Get the vendor ID of a PCI device. Header type independent.
fn get_vendor_id(bus: u8, device: u8, function: u8) -> u16{
pci_config_read_word(bus, device, function, 0)
}
///Get the device ID of a PCI device. Header type independent.
fn get_device_id(bus: u8, device: u8, function: u8) -> u16{
pci_config_read_word(bus, device, function, 0x2)
}
///Get the PCI Device Class of a PCI device. Header type independent.
fn check_pci_device_class(bus: u8, device: u8, function: u8) -> u8{
pci_config_read_word(bus, device, function, 0xA).to_le_bytes()[0]
}
///Get the PCI device subclass of a PCI device. Header type independent.
fn check_pci_device_subclass(bus: u8, device: u8, function: u8) -> u8{
pci_config_read_word(bus, device, function, 0xA).to_le_bytes()[1]
}
Finally, this is the function to check the device.
Code: Select all
///Check a PCI device and return None if the device does not exist or Some<PCIDevice> if it does.
fn check_device(bus: u8, device: u8) -> Option<PCIDevice>{
//FIXME: multiple function devices
let header_type = get_pci_header_type(bus, device);
let vendor_id = get_vendor_id(bus, device, 0);
if vendor_id == 0xFFFF{
return None;
}
//Device vendor is valid
let device_id = get_device_id(bus, device, 0);
let class_id = check_pci_device_class(bus, device, 0);
let subclass_id = check_pci_device_subclass(bus, device, 0);
let mut base_addresses_f1 = None;
if header_type == 0x0{
base_addresses_f1 = Some([
pci_config_read_dword(bus, device, 1, 0x10),
pci_config_read_dword(bus, device, 1, 0x14),
pci_config_read_dword(bus, device, 1, 0x18),
pci_config_read_dword(bus, device, 1, 0x1C),
pci_config_read_dword(bus, device, 1, 0x20),
pci_config_read_dword(bus, device, 1, 0x24),
])
}
//println!("PCI: header type: {:#x}, vendor = {:#x}, device = {:#x}, class = {:#x}, subclass = {:#x}", header_type, vendor_id, device_id, class_id, subclass_id);
Some(PCIDevice{
bus,
device,
vendor_id,
device_id,
subclass_id,
class: class_id.into(),
base_addresses_f1,
header_type
})
}