#include "pci/pci.h" #include #include 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); }