1 #include "pci/pci.h" 2 #include <com32.h> 3 #include <string.h> 4 5 enum pci_config_type __pci_cfg_type; 6 7 static int type1_ok(void) 8 { 9 uint32_t oldcf8, newcf8; 10 11 /* Test for Configuration Method #1 */ 12 13 /* Note: XFree86 writes ~0 and expects to read back 0x80fffffc. Linux 14 does this less severe test; go with Linux. */ 15 16 cli(); 17 outb(1, 0xcfb); /* For old Intel chipsets */ 18 oldcf8 = inl(0xcf8); 19 outl(0x80000000, 0xcf8); 20 newcf8 = inl(0xcf8); 21 outl(oldcf8, 0xcf8); 22 sti(); 23 24 return newcf8 == 0x80000000; 25 } 26 27 static int type2_ok(void) 28 { 29 uint8_t oldcf8, oldcfa; 30 uint8_t cf8, cfa; 31 32 /* Test for Configuration Method #2 */ 33 34 /* CM#2 is hard to probe for, but let's do our best... */ 35 36 cli(); 37 outb(0, 0xcfb); /* For old Intel chipsets */ 38 oldcf8 = inb(0xcf8); 39 outb(0, 0xcf8); 40 oldcfa = inb(0xcfa); 41 outb(0, 0xcfa); 42 43 cf8 = inb(0xcf8); 44 cfa = inb(0xcfa); 45 46 outb(oldcf8, 0xcf8); 47 outb(oldcfa, 0xcfa); 48 sti(); 49 50 return cf8 == 0 && cfa == 0; 51 } 52 53 int pci_set_config_type(enum pci_config_type type) 54 { 55 static const com32sys_t ireg = { 56 .eax.l = 0xb101, 57 .edi.l = 0, 58 .eflags.l = EFLAGS_CF, 59 }; 60 com32sys_t oreg; 61 62 if (type == PCI_CFG_AUTO) { 63 type = PCI_CFG_NONE; 64 65 /* Try to detect PCI BIOS */ 66 __intcall(0x1a, &ireg, &oreg); 67 68 if (!(oreg.eflags.l & EFLAGS_CF) && 69 oreg.eax.b[1] == 0 && oreg.edx.l == 0x20494250) { 70 /* PCI BIOS present. Use direct access if we know how to do it. */ 71 72 if ((oreg.eax.b[0] & 1) && type1_ok()) 73 type = PCI_CFG_TYPE1; 74 else if ((oreg.eax.b[0] & 2) && type2_ok()) 75 type = PCI_CFG_TYPE2; 76 else 77 type = PCI_CFG_BIOS; /* Use BIOS calls as fallback */ 78 79 } else if (type1_ok()) { 80 type = PCI_CFG_TYPE1; 81 } else if (type2_ok()) { 82 type = PCI_CFG_TYPE2; 83 } else { 84 type = PCI_CFG_NONE; /* Badness... */ 85 } 86 } 87 88 return (__pci_cfg_type = type); 89 } 90