Hi,
When reading the PCI space, you need to keep a few things in mind.
The read register is a dword register, but can be read as a byte, word, or dword, as well as reading any one of the bytes within the dword.
For example, the two lines below produce the exact same results:
word = inpw(PCI_DATA + 2);
word = inpd(PCI_DATA) >> 16;
Therefore, you can read any byte, word, or dword at any offset in the PCI space,
with the understanding that you cannot read across a dword boundary. For example, you cannot do:
dword = inpd(PCI_DATA + 2);
expecting to read the high word of the first dword and the low word of the next dword.
With this in mind, the following lines are all valid:
byte = inpb(PCI_DATA + 0);
byte = inpb(PCI_DATA + 1);
byte = inpb(PCI_DATA + 2);
byte = inpb(PCI_DATA + 3);
word = inpw(PCI_DATA + 0);
word = inpw(PCI_DATA + 1);
word = inpw(PCI_DATA + 2);
dword = inpd(PCI_DATA + 0);
However, the following lines are *not* valid:
byte = inpb(PCI_DATA + x); // where x > 3
word = inpw(PCI_DATA + x); // where x > 2
dword = inpd(PCI_DATA + x); // where x > 0
Now, take this in to mind and how about you do the following:
Code: Select all
pci_read_dword(..., ..., offset)
begin
if (offset > 0) then
begin
return (pci_read_word(offset) << 0) | (pci_read_word(offset) << 16)
end
else
return dword
end
Then pci_read_word() does the same thing, but for bytes. i.e.: if the word offset would cross a dword boundary, it calls pci_read_byte twice.
Do you get the idea?
If the current sized read will read across the dword boundary, call the smaller sized read twice, else just read in the sized value.
For example, a dword read from offset 2 in the config space will actually do:
Code: Select all
read_pci_dword calls:
read_pci_word(offset + 0) // offset = 2
read_pci_word(offset + 2) // offset = 2
How above a dword read from offset 3?
Code: Select all
read_pci_dword calls:
read_pci_word calls
read_pci_byte(offset + 0) // offset = 3
read_pci_byte(offset + 1) // offset = 3
read_pci_word(offset + 2) // offset = 3
Two more things:
1) If the first function of a device returns 0xFFFF as the vendor ID, the remaining functions of this device are not valid. They, infact, might return other values, though since the first function returned 0xFFFF, these functions are to be ignored.
2) The first function has a bit in the header that states whether the remaining functions are valid. If this bit indicates there are no more functions, you must skip the remaining 7 functions while enumerating the PCI. As an example, I have an ATA device controller that will return the same data for all 8 functions read even though there is only one valid function. If your PCI enumerator didn't ignore the remaining 7 functions, you might think you have 8 ATA controllers at this device...
Does this help,
Ben
-
http://www.fysnet.net/osdesign_book_series.htm