blob: 896f7e5e5fd4a74bb75c7f7a343133d84aa06d87 [file] [log] [blame]
#include "pci/pci.h"
#include <com32.h>
#include <string.h>
enum pci_config_type __pci_cfg_type;
static int type1_ok(void)
{
uint32_t oldcf8, newcf8;
/* Test for Configuration Method #1 */
/* Note: XFree86 writes ~0 and expects to read back 0x80fffffc. Linux
does this less severe test; go with Linux. */
cli();
outb(1, 0xcfb); /* For old Intel chipsets */
oldcf8 = inl(0xcf8);
outl(0x80000000, 0xcf8);
newcf8 = inl(0xcf8);
outl(oldcf8, 0xcf8);
sti();
return newcf8 == 0x80000000;
}
static int type2_ok(void)
{
uint8_t oldcf8, oldcfa;
uint8_t cf8, cfa;
/* Test for Configuration Method #2 */
/* CM#2 is hard to probe for, but let's do our best... */
cli();
outb(0, 0xcfb); /* For old Intel chipsets */
oldcf8 = inb(0xcf8);
outb(0, 0xcf8);
oldcfa = inb(0xcfa);
outb(0, 0xcfa);
cf8 = inb(0xcf8);
cfa = inb(0xcfa);
outb(oldcf8, 0xcf8);
outb(oldcfa, 0xcfa);
sti();
return cf8 == 0 && cfa == 0;
}
int pci_set_config_type(enum pci_config_type type)
{
static const com32sys_t ireg = {
.eax.l = 0xb101,
.edi.l = 0,
.eflags.l = EFLAGS_CF,
};
com32sys_t oreg;
if (type == PCI_CFG_AUTO) {
type = PCI_CFG_NONE;
/* Try to detect PCI BIOS */
__intcall(0x1a, &ireg, &oreg);
if (!(oreg.eflags.l & EFLAGS_CF) &&
oreg.eax.b[1] == 0 && oreg.edx.l == 0x20494250) {
/* PCI BIOS present. Use direct access if we know how to do it. */
if ((oreg.eax.b[0] & 1) && type1_ok())
type = PCI_CFG_TYPE1;
else if ((oreg.eax.b[0] & 2) && type2_ok())
type = PCI_CFG_TYPE2;
else
type = PCI_CFG_BIOS; /* Use BIOS calls as fallback */
} else if (type1_ok()) {
type = PCI_CFG_TYPE1;
} else if (type2_ok()) {
type = PCI_CFG_TYPE2;
} else {
type = PCI_CFG_NONE; /* Badness... */
}
}
return (__pci_cfg_type = type);
}