summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/com32/lib/pci/cfgtype.c
blob: 896f7e5e5fd4a74bb75c7f7a343133d84aa06d87 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#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);
}