105b261ecSmrg/*
205b261ecSmrg *                   XFree86 int10 module
305b261ecSmrg *   execute BIOS int 10h calls in x86 real mode environment
405b261ecSmrg *                 Copyright 1999 Egbert Eich
505b261ecSmrg *
605b261ecSmrg *   Part of this code was inspired  by the VBIOS POSTing code in DOSEMU
705b261ecSmrg *   developed by the "DOSEMU-Development-Team"
805b261ecSmrg */
905b261ecSmrg
1005b261ecSmrg/*
1105b261ecSmrg * To debug port accesses define PRINT_PORT to 1.
1205b261ecSmrg * Note! You also have to comment out ioperm()
1305b261ecSmrg * in xf86EnableIO(). Otherwise we won't trap
1405b261ecSmrg * on PIO.
1505b261ecSmrg */
1605b261ecSmrg
1705b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
1805b261ecSmrg#include <xorg-config.h>
1905b261ecSmrg#endif
2005b261ecSmrg
2105b261ecSmrg#define PRINT_PORT 0
2205b261ecSmrg
2305b261ecSmrg#include <unistd.h>
2405b261ecSmrg
2505b261ecSmrg#include <X11/Xos.h>
2605b261ecSmrg#include "xf86.h"
2705b261ecSmrg#include "xf86_OSproc.h"
2805b261ecSmrg#include "compiler.h"
2905b261ecSmrg#define _INT10_PRIVATE
3005b261ecSmrg#include "int10Defines.h"
3105b261ecSmrg#include "xf86int10.h"
324642e01fSmrg#include "Pci.h"
3305b261ecSmrg#ifdef _X86EMU
3405b261ecSmrg#include "x86emu/x86emui.h"
354642e01fSmrg#else
364642e01fSmrg#define DEBUG_IO_TRACE() 0
3705b261ecSmrg#endif
384642e01fSmrg#include <pciaccess.h>
3905b261ecSmrg
40f7df2e56Smrgstatic int pciCfg1in(uint16_t addr, uint32_t *val);
41f7df2e56Smrgstatic int pciCfg1out(uint16_t addr, uint32_t val);
42f7df2e56Smrgstatic int pciCfg1inw(uint16_t addr, uint16_t *val);
43f7df2e56Smrgstatic int pciCfg1outw(uint16_t addr, uint16_t val);
44f7df2e56Smrgstatic int pciCfg1inb(uint16_t addr, uint8_t *val);
45f7df2e56Smrgstatic int pciCfg1outb(uint16_t addr, uint8_t val);
46f7df2e56Smrg
4705b261ecSmrg#if defined (_PC)
4805b261ecSmrgstatic void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set);
4905b261ecSmrg#endif
5005b261ecSmrg
5105b261ecSmrg#define REG pInt
5205b261ecSmrg
5305b261ecSmrgint
5405b261ecSmrgsetup_int(xf86Int10InfoPtr pInt)
5505b261ecSmrg{
5605b261ecSmrg    if (pInt != Int10Current) {
57f7df2e56Smrg        if (!MapCurrentInt10(pInt))
58f7df2e56Smrg            return -1;
59f7df2e56Smrg        Int10Current = pInt;
60f7df2e56Smrg    }
61f7df2e56Smrg    X86_EAX = (uint32_t) pInt->ax;
62f7df2e56Smrg    X86_EBX = (uint32_t) pInt->bx;
63f7df2e56Smrg    X86_ECX = (uint32_t) pInt->cx;
64f7df2e56Smrg    X86_EDX = (uint32_t) pInt->dx;
65f7df2e56Smrg    X86_ESI = (uint32_t) pInt->si;
66f7df2e56Smrg    X86_EDI = (uint32_t) pInt->di;
67f7df2e56Smrg    X86_EBP = (uint32_t) pInt->bp;
68f7df2e56Smrg    X86_ESP = 0x1000;
69f7df2e56Smrg    X86_SS = pInt->stackseg >> 4;
70f7df2e56Smrg    X86_EIP = 0x0600;
71f7df2e56Smrg    X86_CS = 0x0;               /* address of 'hlt' */
72f7df2e56Smrg    X86_DS = 0x40;              /* standard pc ds */
7305b261ecSmrg    X86_ES = pInt->es;
7405b261ecSmrg    X86_FS = 0;
7505b261ecSmrg    X86_GS = 0;
7605b261ecSmrg    X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;
7705b261ecSmrg#if defined (_PC)
7805b261ecSmrg    if (pInt->Flags & SET_BIOS_SCRATCH)
79f7df2e56Smrg        SetResetBIOSVars(pInt, TRUE);
8005b261ecSmrg#endif
8165b04b38Smrg    OsBlockSignals();
8265b04b38Smrg    return 0;
8305b261ecSmrg}
8405b261ecSmrg
8505b261ecSmrgvoid
8605b261ecSmrgfinish_int(xf86Int10InfoPtr pInt, int sig)
8705b261ecSmrg{
8865b04b38Smrg    OsReleaseSignals();
89f7df2e56Smrg    pInt->ax = (uint32_t) X86_EAX;
90f7df2e56Smrg    pInt->bx = (uint32_t) X86_EBX;
91f7df2e56Smrg    pInt->cx = (uint32_t) X86_ECX;
92f7df2e56Smrg    pInt->dx = (uint32_t) X86_EDX;
93f7df2e56Smrg    pInt->si = (uint32_t) X86_ESI;
94f7df2e56Smrg    pInt->di = (uint32_t) X86_EDI;
95f7df2e56Smrg    pInt->es = (uint16_t) X86_ES;
96f7df2e56Smrg    pInt->bp = (uint32_t) X86_EBP;
97f7df2e56Smrg    pInt->flags = (uint32_t) X86_FLAGS;
9805b261ecSmrg#if defined (_PC)
9905b261ecSmrg    if (pInt->Flags & RESTORE_BIOS_SCRATCH)
100f7df2e56Smrg        SetResetBIOSVars(pInt, FALSE);
10105b261ecSmrg#endif
10205b261ecSmrg}
10305b261ecSmrg
10405b261ecSmrg/* general software interrupt handler */
105f7df2e56Smrguint32_t
106f7df2e56SmrggetIntVect(xf86Int10InfoPtr pInt, int num)
10705b261ecSmrg{
10805b261ecSmrg    return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4);
10905b261ecSmrg}
11005b261ecSmrg
11105b261ecSmrgvoid
112f7df2e56Smrgpushw(xf86Int10InfoPtr pInt, uint16_t val)
11305b261ecSmrg{
11405b261ecSmrg    X86_ESP -= 2;
115f7df2e56Smrg    MEM_WW(pInt, ((uint32_t) X86_SS << 4) + X86_SP, val);
11605b261ecSmrg}
11705b261ecSmrg
11805b261ecSmrgint
11905b261ecSmrgrun_bios_int(int num, xf86Int10InfoPtr pInt)
12005b261ecSmrg{
121f7df2e56Smrg    uint32_t eflags;
122f7df2e56Smrg
12305b261ecSmrg#ifndef _PC
12405b261ecSmrg    /* check if bios vector is initialized */
125f7df2e56Smrg    if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) {      /* SYS_BIOS_SEG ? */
126f7df2e56Smrg
127f7df2e56Smrg        if (num == 21 && X86_AH == 0x4e) {
128f7df2e56Smrg            xf86DrvMsg(pInt->pScrn->scrnIndex, X_NOTICE,
129f7df2e56Smrg                       "Failing Find-Matching-File on non-PC"
130f7df2e56Smrg                       " (int 21, func 4e)\n");
131f7df2e56Smrg            X86_AX = 2;
132f7df2e56Smrg            SET_FLAG(F_CF);
133f7df2e56Smrg            return 1;
134f7df2e56Smrg        }
135f7df2e56Smrg        else {
136f7df2e56Smrg            xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
137f7df2e56Smrg                           "Ignoring int 0x%02x call\n", num);
138f7df2e56Smrg            if (xf86GetVerbosity() > 3) {
139f7df2e56Smrg                dump_registers(pInt);
140f7df2e56Smrg                stack_trace(pInt);
141f7df2e56Smrg            }
142f7df2e56Smrg            return 1;
143f7df2e56Smrg        }
14405b261ecSmrg    }
14505b261ecSmrg#endif
14605b261ecSmrg#ifdef PRINT_INT
14705b261ecSmrg    ErrorF("calling card BIOS at: ");
14805b261ecSmrg#endif
14905b261ecSmrg    eflags = X86_EFLAGS;
15005b261ecSmrg#if 0
15105b261ecSmrg    eflags = eflags | IF_MASK;
152f7df2e56Smrg    X86_EFLAGS = X86_EFLAGS & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK);
15305b261ecSmrg#endif
15405b261ecSmrg    pushw(pInt, eflags);
15505b261ecSmrg    pushw(pInt, X86_CS);
15605b261ecSmrg    pushw(pInt, X86_IP);
15705b261ecSmrg    X86_CS = MEM_RW(pInt, (num << 2) + 2);
158f7df2e56Smrg    X86_IP = MEM_RW(pInt, num << 2);
15905b261ecSmrg#ifdef PRINT_INT
16005b261ecSmrg    ErrorF("0x%x:%lx\n", X86_CS, X86_EIP);
16105b261ecSmrg#endif
16205b261ecSmrg    return 1;
16305b261ecSmrg}
16405b261ecSmrg
16505b261ecSmrg/* Debugging stuff */
16605b261ecSmrgvoid
16705b261ecSmrgdump_code(xf86Int10InfoPtr pInt)
16805b261ecSmrg{
16905b261ecSmrg    int i;
170f7df2e56Smrg    uint32_t lina = SEG_ADR((uint32_t), X86_CS, IP);
17105b261ecSmrg
172f7df2e56Smrg    xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3, "code at 0x%8.8" PRIx32 ":\n",
173f7df2e56Smrg                   (unsigned) lina);
174f7df2e56Smrg    for (i = 0; i < 0x10; i++)
175f7df2e56Smrg        xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
17605b261ecSmrg    xf86ErrorFVerb(3, "\n");
177f7df2e56Smrg    for (; i < 0x20; i++)
178f7df2e56Smrg        xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
17905b261ecSmrg    xf86ErrorFVerb(3, "\n");
18005b261ecSmrg}
18105b261ecSmrg
18205b261ecSmrgvoid
18305b261ecSmrgdump_registers(xf86Int10InfoPtr pInt)
18405b261ecSmrg{
185f7df2e56Smrg    xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3,
186f7df2e56Smrg                   "EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n",
187f7df2e56Smrg                   (unsigned long) X86_EAX, (unsigned long) X86_EBX,
188f7df2e56Smrg                   (unsigned long) X86_ECX, (unsigned long) X86_EDX);
189f7df2e56Smrg    xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3,
190f7df2e56Smrg                   "ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n",
191f7df2e56Smrg                   (unsigned long) X86_ESP, (unsigned long) X86_EBP,
192f7df2e56Smrg                   (unsigned long) X86_ESI, (unsigned long) X86_EDI);
193f7df2e56Smrg    xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3,
194f7df2e56Smrg                   "CS=0x%4.4x, SS=0x%4.4x,"
195f7df2e56Smrg                   " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n",
196f7df2e56Smrg                   X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS);
197f7df2e56Smrg    xf86DrvMsgVerb(pInt->pScrn->scrnIndex, X_INFO, 3,
198f7df2e56Smrg                   "EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n",
199f7df2e56Smrg                   (unsigned long) X86_EIP, (unsigned long) X86_EFLAGS);
20005b261ecSmrg}
20105b261ecSmrg
20205b261ecSmrgvoid
20305b261ecSmrgstack_trace(xf86Int10InfoPtr pInt)
20405b261ecSmrg{
20505b261ecSmrg    int i = 0;
206f7df2e56Smrg    unsigned long stack = SEG_ADR((uint32_t), X86_SS, SP);
207f7df2e56Smrg    unsigned long tail = (uint32_t) ((X86_SS << 4) + 0x1000);
20805b261ecSmrg
209f7df2e56Smrg    if (stack >= tail)
210f7df2e56Smrg        return;
21105b261ecSmrg
21205b261ecSmrg    xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack);
21305b261ecSmrg    for (; stack < tail; stack++) {
214f7df2e56Smrg        xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack));
215f7df2e56Smrg        i = (i + 1) % 0x10;
216f7df2e56Smrg        if (!i)
217f7df2e56Smrg            xf86ErrorFVerb(3, "\n");
21805b261ecSmrg    }
21905b261ecSmrg    if (i)
220f7df2e56Smrg        xf86ErrorFVerb(3, "\n");
22105b261ecSmrg}
22205b261ecSmrg
22305b261ecSmrgint
22405b261ecSmrgport_rep_inb(xf86Int10InfoPtr pInt,
225f7df2e56Smrg             uint16_t port, uint32_t base, int d_f, uint32_t count)
22605b261ecSmrg{
22705b261ecSmrg    register int inc = d_f ? -1 : 1;
228f7df2e56Smrg    uint32_t dst = base;
229f7df2e56Smrg
23005b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
231f7df2e56Smrg        ErrorF(" rep_insb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
232f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
23305b261ecSmrg    while (count--) {
234f7df2e56Smrg        MEM_WB(pInt, dst, x_inb(port));
235f7df2e56Smrg        dst += inc;
23605b261ecSmrg    }
23705b261ecSmrg    return dst - base;
23805b261ecSmrg}
23905b261ecSmrg
24005b261ecSmrgint
24105b261ecSmrgport_rep_inw(xf86Int10InfoPtr pInt,
242f7df2e56Smrg             uint16_t port, uint32_t base, int d_f, uint32_t count)
24305b261ecSmrg{
24405b261ecSmrg    register int inc = d_f ? -2 : 2;
245f7df2e56Smrg    uint32_t dst = base;
246f7df2e56Smrg
24705b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
248f7df2e56Smrg        ErrorF(" rep_insw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
249f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
25005b261ecSmrg    while (count--) {
251f7df2e56Smrg        MEM_WW(pInt, dst, x_inw(port));
252f7df2e56Smrg        dst += inc;
25305b261ecSmrg    }
25405b261ecSmrg    return dst - base;
25505b261ecSmrg}
25605b261ecSmrg
25705b261ecSmrgint
25805b261ecSmrgport_rep_inl(xf86Int10InfoPtr pInt,
259f7df2e56Smrg             uint16_t port, uint32_t base, int d_f, uint32_t count)
26005b261ecSmrg{
26105b261ecSmrg    register int inc = d_f ? -4 : 4;
262f7df2e56Smrg    uint32_t dst = base;
263f7df2e56Smrg
26405b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
265f7df2e56Smrg        ErrorF(" rep_insl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
266f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
26705b261ecSmrg    while (count--) {
268f7df2e56Smrg        MEM_WL(pInt, dst, x_inl(port));
269f7df2e56Smrg        dst += inc;
27005b261ecSmrg    }
27105b261ecSmrg    return dst - base;
27205b261ecSmrg}
27305b261ecSmrg
27405b261ecSmrgint
27505b261ecSmrgport_rep_outb(xf86Int10InfoPtr pInt,
276f7df2e56Smrg              uint16_t port, uint32_t base, int d_f, uint32_t count)
27705b261ecSmrg{
27805b261ecSmrg    register int inc = d_f ? -1 : 1;
279f7df2e56Smrg    uint32_t dst = base;
280f7df2e56Smrg
28105b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
282f7df2e56Smrg        ErrorF(" rep_outb(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
283f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
28405b261ecSmrg    while (count--) {
285f7df2e56Smrg        x_outb(port, MEM_RB(pInt, dst));
286f7df2e56Smrg        dst += inc;
28705b261ecSmrg    }
28805b261ecSmrg    return dst - base;
28905b261ecSmrg}
29005b261ecSmrg
29105b261ecSmrgint
29205b261ecSmrgport_rep_outw(xf86Int10InfoPtr pInt,
293f7df2e56Smrg              uint16_t port, uint32_t base, int d_f, uint32_t count)
29405b261ecSmrg{
29505b261ecSmrg    register int inc = d_f ? -2 : 2;
296f7df2e56Smrg    uint32_t dst = base;
297f7df2e56Smrg
29805b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
299f7df2e56Smrg        ErrorF(" rep_outw(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
300f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
30105b261ecSmrg    while (count--) {
302f7df2e56Smrg        x_outw(port, MEM_RW(pInt, dst));
303f7df2e56Smrg        dst += inc;
30405b261ecSmrg    }
30505b261ecSmrg    return dst - base;
30605b261ecSmrg}
30705b261ecSmrg
30805b261ecSmrgint
30905b261ecSmrgport_rep_outl(xf86Int10InfoPtr pInt,
310f7df2e56Smrg              uint16_t port, uint32_t base, int d_f, uint32_t count)
31105b261ecSmrg{
31205b261ecSmrg    register int inc = d_f ? -4 : 4;
313f7df2e56Smrg    uint32_t dst = base;
314f7df2e56Smrg
31505b261ecSmrg    if (PRINT_PORT && DEBUG_IO_TRACE())
316f7df2e56Smrg        ErrorF(" rep_outl(%#x) %" PRIu32 " bytes at %8.8" PRIx32 " %s\n",
317f7df2e56Smrg               port, (unsigned) count, (unsigned) base, d_f ? "up" : "down");
31805b261ecSmrg    while (count--) {
319f7df2e56Smrg        x_outl(port, MEM_RL(pInt, dst));
320f7df2e56Smrg        dst += inc;
32105b261ecSmrg    }
32205b261ecSmrg    return dst - base;
32305b261ecSmrg}
32405b261ecSmrg
325f7df2e56Smrguint8_t
326f7df2e56Smrgx_inb(uint16_t port)
32705b261ecSmrg{
328f7df2e56Smrg    uint8_t val;
32905b261ecSmrg
33005b261ecSmrg    if (port == 0x40) {
331f7df2e56Smrg        Int10Current->inb40time++;
332f7df2e56Smrg        val = (uint8_t) (Int10Current->inb40time >>
333f7df2e56Smrg                       ((Int10Current->inb40time & 1) << 3));
334f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
335f7df2e56Smrg            ErrorF(" inb(%#x) = %2.2x\n", port, val);
33605b261ecSmrg#ifdef __NOT_YET__
337f7df2e56Smrg    }
338f7df2e56Smrg    else if (port < 0x0100) {   /* Don't interfere with mainboard */
339f7df2e56Smrg        val = 0;
340f7df2e56Smrg        xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
341f7df2e56Smrg                       "inb 0x%4.4x\n", port);
342f7df2e56Smrg        if (xf86GetVerbosity() > 3) {
343f7df2e56Smrg            dump_registers(Int10Current);
344f7df2e56Smrg            stack_trace(Int10Current);
345f7df2e56Smrg        }
346f7df2e56Smrg#endif                          /* __NOT_YET__ */
347f7df2e56Smrg    }
348f7df2e56Smrg    else if (!pciCfg1inb(port, &val)) {
349f7df2e56Smrg        val = pci_io_read8(Int10Current->io, port);
350f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
351f7df2e56Smrg            ErrorF(" inb(%#x) = %2.2x\n", port, val);
35205b261ecSmrg    }
35305b261ecSmrg    return val;
35405b261ecSmrg}
35505b261ecSmrg
356f7df2e56Smrguint16_t
357f7df2e56Smrgx_inw(uint16_t port)
35805b261ecSmrg{
359f7df2e56Smrg    uint16_t val;
36005b261ecSmrg
36105b261ecSmrg    if (port == 0x5c) {
362f7df2e56Smrg        struct timeval tv;
363f7df2e56Smrg
364f7df2e56Smrg        /*
365f7df2e56Smrg         * Emulate a PC's timer.  Typical resolution is 3.26 usec.
366f7df2e56Smrg         * Approximate this by dividing by 3.
367f7df2e56Smrg         */
368f7df2e56Smrg        X_GETTIMEOFDAY(&tv);
369f7df2e56Smrg        val = (uint16_t) (tv.tv_usec / 3);
370f7df2e56Smrg    }
371f7df2e56Smrg    else if (!pciCfg1inw(port, &val)) {
372f7df2e56Smrg        val = pci_io_read16(Int10Current->io, port);
373f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
374f7df2e56Smrg            ErrorF(" inw(%#x) = %4.4x\n", port, val);
37505b261ecSmrg    }
37605b261ecSmrg    return val;
37705b261ecSmrg}
37805b261ecSmrg
37905b261ecSmrgvoid
380f7df2e56Smrgx_outb(uint16_t port, uint8_t val)
38105b261ecSmrg{
38205b261ecSmrg    if ((port == 0x43) && (val == 0)) {
383f7df2e56Smrg        struct timeval tv;
384f7df2e56Smrg
385f7df2e56Smrg        /*
386f7df2e56Smrg         * Emulate a PC's timer 0.  Such timers typically have a resolution of
387f7df2e56Smrg         * some .838 usec per tick, but this can only provide 1 usec per tick.
388f7df2e56Smrg         * (Not that this matters much, given inherent emulation delays.)  Use
389f7df2e56Smrg         * the bottom bit as a byte select.  See inb(0x40) above.
390f7df2e56Smrg         */
391f7df2e56Smrg        X_GETTIMEOFDAY(&tv);
392f7df2e56Smrg        Int10Current->inb40time = (uint16_t) (tv.tv_usec | 1);
393f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
394f7df2e56Smrg            ErrorF(" outb(%#x, %2.2x)\n", port, val);
39505b261ecSmrg#ifdef __NOT_YET__
396f7df2e56Smrg    }
397f7df2e56Smrg    else if (port < 0x0100) {   /* Don't interfere with mainboard */
398f7df2e56Smrg        xf86DrvMsgVerb(Int10Current->pScrn->scrnIndex, X_NOT_IMPLEMENTED, 2,
399f7df2e56Smrg                       "outb 0x%4.4x,0x%2.2x\n", port, val);
400f7df2e56Smrg        if (xf86GetVerbosity() > 3) {
401f7df2e56Smrg            dump_registers(Int10Current);
402f7df2e56Smrg            stack_trace(Int10Current);
403f7df2e56Smrg        }
404f7df2e56Smrg#endif                          /* __NOT_YET__ */
405f7df2e56Smrg    }
406f7df2e56Smrg    else if (!pciCfg1outb(port, val)) {
407f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
408f7df2e56Smrg            ErrorF(" outb(%#x, %2.2x)\n", port, val);
409f7df2e56Smrg        pci_io_write8(Int10Current->io, port, val);
41005b261ecSmrg    }
41105b261ecSmrg}
41205b261ecSmrg
41305b261ecSmrgvoid
414f7df2e56Smrgx_outw(uint16_t port, uint16_t val)
41505b261ecSmrg{
41605b261ecSmrg
41705b261ecSmrg    if (!pciCfg1outw(port, val)) {
418f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
419f7df2e56Smrg            ErrorF(" outw(%#x, %4.4x)\n", port, val);
420f7df2e56Smrg        pci_io_write16(Int10Current->io, port, val);
42105b261ecSmrg    }
42205b261ecSmrg}
42305b261ecSmrg
424f7df2e56Smrguint32_t
425f7df2e56Smrgx_inl(uint16_t port)
42605b261ecSmrg{
427f7df2e56Smrg    uint32_t val;
42805b261ecSmrg
42905b261ecSmrg    if (!pciCfg1in(port, &val)) {
430f7df2e56Smrg        val = pci_io_read32(Int10Current->io, port);
431f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
432f7df2e56Smrg            ErrorF(" inl(%#x) = %8.8" PRIx32 "\n", port, (unsigned) val);
43305b261ecSmrg    }
43405b261ecSmrg    return val;
43505b261ecSmrg}
43605b261ecSmrg
43705b261ecSmrgvoid
438f7df2e56Smrgx_outl(uint16_t port, uint32_t val)
43905b261ecSmrg{
44005b261ecSmrg    if (!pciCfg1out(port, val)) {
441f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
442f7df2e56Smrg            ErrorF(" outl(%#x, %8.8" PRIx32 ")\n", port, (unsigned) val);
443f7df2e56Smrg        pci_io_write32(Int10Current->io, port, val);
44405b261ecSmrg    }
44505b261ecSmrg}
44605b261ecSmrg
447f7df2e56Smrguint8_t
448f7df2e56SmrgMem_rb(uint32_t addr)
44905b261ecSmrg{
450f7df2e56Smrg    return (*Int10Current->mem->rb) (Int10Current, addr);
45105b261ecSmrg}
45205b261ecSmrg
453f7df2e56Smrguint16_t
454f7df2e56SmrgMem_rw(uint32_t addr)
45505b261ecSmrg{
456f7df2e56Smrg    return (*Int10Current->mem->rw) (Int10Current, addr);
45705b261ecSmrg}
45805b261ecSmrg
459f7df2e56Smrguint32_t
460f7df2e56SmrgMem_rl(uint32_t addr)
46105b261ecSmrg{
462f7df2e56Smrg    return (*Int10Current->mem->rl) (Int10Current, addr);
46305b261ecSmrg}
46405b261ecSmrg
46505b261ecSmrgvoid
466f7df2e56SmrgMem_wb(uint32_t addr, uint8_t val)
46705b261ecSmrg{
468f7df2e56Smrg    (*Int10Current->mem->wb) (Int10Current, addr, val);
46905b261ecSmrg}
47005b261ecSmrg
47105b261ecSmrgvoid
472f7df2e56SmrgMem_ww(uint32_t addr, uint16_t val)
47305b261ecSmrg{
474f7df2e56Smrg    (*Int10Current->mem->ww) (Int10Current, addr, val);
47505b261ecSmrg}
47605b261ecSmrg
47705b261ecSmrgvoid
478f7df2e56SmrgMem_wl(uint32_t addr, uint32_t val)
47905b261ecSmrg{
480f7df2e56Smrg    (*Int10Current->mem->wl) (Int10Current, addr, val);
48105b261ecSmrg}
48205b261ecSmrg
483f7df2e56Smrgstatic uint32_t PciCfg1Addr = 0;
48405b261ecSmrg
48565b04b38Smrg#define PCI_DOM_FROM_TAG(tag)  (((tag) >> 24) & (PCI_DOM_MASK))
48665b04b38Smrg#define PCI_BUS_FROM_TAG(tag)  (((tag) >> 16) & (PCI_DOMBUS_MASK))
48765b04b38Smrg#define PCI_DEV_FROM_TAG(tag)  (((tag) & 0x0000f800u) >> 11)
48865b04b38Smrg#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8)
48965b04b38Smrg
4904642e01fSmrg#define PCI_OFFSET(x) ((x) & 0x000000ff)
4914642e01fSmrg#define PCI_TAG(x)    ((x) & 0x7fffff00)
4924642e01fSmrg
493f7df2e56Smrgstatic struct pci_device *
494f7df2e56Smrgpci_device_for_cfg_address(uint32_t addr)
4954642e01fSmrg{
496f7df2e56Smrg    struct pci_device *dev = NULL;
497f7df2e56Smrg    uint32_t tag = PCI_TAG(addr);
4984642e01fSmrg
499f7df2e56Smrg    struct pci_slot_match slot_match = {
500f7df2e56Smrg        .domain = PCI_DOM_FROM_TAG(tag),
501f7df2e56Smrg        .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)),
502f7df2e56Smrg        .dev = PCI_DEV_FROM_TAG(tag),
503f7df2e56Smrg        .func = PCI_FUNC_FROM_TAG(tag),
504f7df2e56Smrg        .match_data = 0
505f7df2e56Smrg    };
5064642e01fSmrg
507f7df2e56Smrg    struct pci_device_iterator *iter =
508f7df2e56Smrg        pci_slot_match_iterator_create(&slot_match);
5094642e01fSmrg
510f7df2e56Smrg    if (iter)
511f7df2e56Smrg        dev = pci_device_next(iter);
5124642e01fSmrg
513f7df2e56Smrg    pci_iterator_destroy(iter);
514f7df2e56Smrg
515f7df2e56Smrg    return dev;
5164642e01fSmrg}
51705b261ecSmrg
51805b261ecSmrgstatic int
519f7df2e56SmrgpciCfg1in(uint16_t addr, uint32_t *val)
52005b261ecSmrg{
52105b261ecSmrg    if (addr == 0xCF8) {
522f7df2e56Smrg        *val = PciCfg1Addr;
523f7df2e56Smrg        return 1;
52405b261ecSmrg    }
52505b261ecSmrg    if (addr == 0xCFC) {
526f7df2e56Smrg        pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr),
527f7df2e56Smrg				/*
528f7df2e56Smrg				 * XXXMRG
529f7df2e56Smrg				 * this one is OK - CARD32 is "long" for 32 bit
530f7df2e56Smrg				 * and "int" for 64 bit
531f7df2e56Smrg				 */
532f7df2e56Smrg                                (uint32_t *) val, PCI_OFFSET(PciCfg1Addr));
533f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
534f7df2e56Smrg            ErrorF(" cfg_inl(%#" PRIx32 ") = %8.8" PRIx32 "\n", (unsigned) PciCfg1Addr,
535f7df2e56Smrg                   (unsigned) *val);
536f7df2e56Smrg        return 1;
53705b261ecSmrg    }
53805b261ecSmrg    return 0;
53905b261ecSmrg}
54005b261ecSmrg
54105b261ecSmrgstatic int
542f7df2e56SmrgpciCfg1out(uint16_t addr, uint32_t val)
54305b261ecSmrg{
54405b261ecSmrg    if (addr == 0xCF8) {
545f7df2e56Smrg        PciCfg1Addr = val;
546f7df2e56Smrg        return 1;
54705b261ecSmrg    }
54805b261ecSmrg    if (addr == 0xCFC) {
549f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
550f7df2e56Smrg            ErrorF(" cfg_outl(%#" PRIx32 ", %8.8" PRIx32 ")\n", (unsigned) PciCfg1Addr,
551f7df2e56Smrg                   (unsigned) val);
552f7df2e56Smrg        pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), val,
553f7df2e56Smrg                                 PCI_OFFSET(PciCfg1Addr));
554f7df2e56Smrg        return 1;
55505b261ecSmrg    }
55605b261ecSmrg    return 0;
55705b261ecSmrg}
55805b261ecSmrg
55905b261ecSmrgstatic int
560f7df2e56SmrgpciCfg1inw(uint16_t addr, uint16_t *val)
56105b261ecSmrg{
5624642e01fSmrg    int shift;
56305b261ecSmrg
56405b261ecSmrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
565f7df2e56Smrg        shift = (addr - 0xCF8) * 8;
566f7df2e56Smrg        *val = (PciCfg1Addr >> shift) & 0xffff;
567f7df2e56Smrg        return 1;
56805b261ecSmrg    }
56905b261ecSmrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
570f7df2e56Smrg        const unsigned offset = addr - 0xCFC;
571f7df2e56Smrg
572f7df2e56Smrg        pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr),
573f7df2e56Smrg                                val, PCI_OFFSET(PciCfg1Addr) + offset);
574f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
575f7df2e56Smrg            ErrorF(" cfg_inw(%#" PRIx32 ") = %4.4x\n", (unsigned) (PciCfg1Addr + offset),
576f7df2e56Smrg                   (unsigned) *val);
577f7df2e56Smrg        return 1;
57805b261ecSmrg    }
57905b261ecSmrg    return 0;
58005b261ecSmrg}
58105b261ecSmrg
58205b261ecSmrgstatic int
583f7df2e56SmrgpciCfg1outw(uint16_t addr, uint16_t val)
58405b261ecSmrg{
5854642e01fSmrg    int shift;
58605b261ecSmrg
58705b261ecSmrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
588f7df2e56Smrg        shift = (addr - 0xCF8) * 8;
589f7df2e56Smrg        PciCfg1Addr &= ~(0xffff << shift);
590f7df2e56Smrg        PciCfg1Addr |= ((uint32_t) val) << shift;
591f7df2e56Smrg        return 1;
59205b261ecSmrg    }
59305b261ecSmrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
594f7df2e56Smrg        const unsigned offset = addr - 0xCFC;
595f7df2e56Smrg
596f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
597f7df2e56Smrg            ErrorF(" cfg_outw(%#" PRIx32 ", %4.4x)\n", (unsigned) (PciCfg1Addr + offset),
598f7df2e56Smrg                   (unsigned) val);
599f7df2e56Smrg        pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), val,
600f7df2e56Smrg                                 PCI_OFFSET(PciCfg1Addr) + offset);
601f7df2e56Smrg        return 1;
60205b261ecSmrg    }
60305b261ecSmrg    return 0;
60405b261ecSmrg}
60505b261ecSmrg
60605b261ecSmrgstatic int
607f7df2e56SmrgpciCfg1inb(uint16_t addr, uint8_t *val)
60805b261ecSmrg{
6094642e01fSmrg    int shift;
61005b261ecSmrg
61105b261ecSmrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
612f7df2e56Smrg        shift = (addr - 0xCF8) * 8;
613f7df2e56Smrg        *val = (PciCfg1Addr >> shift) & 0xff;
614f7df2e56Smrg        return 1;
61505b261ecSmrg    }
61605b261ecSmrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
617f7df2e56Smrg        const unsigned offset = addr - 0xCFC;
618f7df2e56Smrg
619f7df2e56Smrg        pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr),
620f7df2e56Smrg                               val, PCI_OFFSET(PciCfg1Addr) + offset);
621f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
622f7df2e56Smrg            ErrorF(" cfg_inb(%#" PRIx32 ") = %2.2x\n", (unsigned) (PciCfg1Addr + offset),
623f7df2e56Smrg                   (unsigned) *val);
624f7df2e56Smrg        return 1;
62505b261ecSmrg    }
62605b261ecSmrg    return 0;
62705b261ecSmrg}
62805b261ecSmrg
62905b261ecSmrgstatic int
630f7df2e56SmrgpciCfg1outb(uint16_t addr, uint8_t val)
63105b261ecSmrg{
6324642e01fSmrg    int shift;
63305b261ecSmrg
63405b261ecSmrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
635f7df2e56Smrg        shift = (addr - 0xCF8) * 8;
636f7df2e56Smrg        PciCfg1Addr &= ~(0xff << shift);
637f7df2e56Smrg        PciCfg1Addr |= ((uint32_t) val) << shift;
638f7df2e56Smrg        return 1;
63905b261ecSmrg    }
64005b261ecSmrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
641f7df2e56Smrg        const unsigned offset = addr - 0xCFC;
642f7df2e56Smrg
643f7df2e56Smrg        if (PRINT_PORT && DEBUG_IO_TRACE())
644f7df2e56Smrg            ErrorF(" cfg_outb(%#" PRIx32 ", %2.2x)\n", (unsigned) (PciCfg1Addr + offset),
645f7df2e56Smrg                   (unsigned) val);
646f7df2e56Smrg        pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), val,
647f7df2e56Smrg                                PCI_OFFSET(PciCfg1Addr) + offset);
648f7df2e56Smrg        return 1;
64905b261ecSmrg    }
65005b261ecSmrg    return 0;
65105b261ecSmrg}
65205b261ecSmrg
653f7df2e56Smrguint8_t
654f7df2e56Smrgbios_checksum(const uint8_t *start, int size)
65505b261ecSmrg{
656f7df2e56Smrg    uint8_t sum = 0;
65705b261ecSmrg
65805b261ecSmrg    while (size-- > 0)
659f7df2e56Smrg        sum += *start++;
66005b261ecSmrg    return sum;
66105b261ecSmrg}
66205b261ecSmrg
66305b261ecSmrg/*
66405b261ecSmrg * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make
66505b261ecSmrg * an attempt to detect a legacy ISA card. If they find one they might
66605b261ecSmrg * act very strange: for example they might configure the card as a
66705b261ecSmrg * monochrome card. This might cause some drivers to choke.
6685a112b11Smrg * To avoid this we attempt legacy VGA by writing to all known VGA
66905b261ecSmrg * disable registers before we call the BIOS initialization and
6705a112b11Smrg * restore the original values afterwards. In between we hold our
6715a112b11Smrg * breath. To get to a (possibly existing) ISA card need to disable
67205b261ecSmrg * our current PCI card.
67305b261ecSmrg */
67405b261ecSmrg/*
67505b261ecSmrg * This is just for booting: we just want to catch pure
67605b261ecSmrg * legacy vga therefore we don't worry about mmio etc.
67705b261ecSmrg * This stuff should really go into vgaHW.c. However then
67805b261ecSmrg * the driver would have to load the vga-module prior to
67905b261ecSmrg * doing int10.
68005b261ecSmrg */
68105b261ecSmrgvoid
68205b261ecSmrgLockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
68305b261ecSmrg{
684af31da9aSmacallan#ifndef NO_LEGACY_VGA
685f7df2e56Smrg    vga->save_msr = pci_io_read8(pInt->io, 0x03CC);
686f7df2e56Smrg    vga->save_vse = pci_io_read8(pInt->io, 0x03C3);
68705b261ecSmrg#ifndef __ia64__
688f7df2e56Smrg    vga->save_46e8 = pci_io_read8(pInt->io, 0x46E8);
68905b261ecSmrg#endif
690f7df2e56Smrg    vga->save_pos102 = pci_io_read8(pInt->io, 0x0102);
691f7df2e56Smrg    pci_io_write8(pInt->io, 0x03C2, ~(uint8_t) 0x03 & vga->save_msr);
692f7df2e56Smrg    pci_io_write8(pInt->io, 0x03C3, ~(uint8_t) 0x01 & vga->save_vse);
69305b261ecSmrg#ifndef __ia64__
694f7df2e56Smrg    pci_io_write8(pInt->io, 0x46E8, ~(uint8_t) 0x08 & vga->save_46e8);
69505b261ecSmrg#endif
696f7df2e56Smrg    pci_io_write8(pInt->io, 0x0102, ~(uint8_t) 0x01 & vga->save_pos102);
697af31da9aSmacallan#endif
69805b261ecSmrg}
69905b261ecSmrg
70005b261ecSmrgvoid
70105b261ecSmrgUnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
70205b261ecSmrg{
703af31da9aSmacallan#ifndef NO_LEGACY_VGA
704f7df2e56Smrg    pci_io_write8(pInt->io, 0x0102, vga->save_pos102);
70505b261ecSmrg#ifndef __ia64__
706f7df2e56Smrg    pci_io_write8(pInt->io, 0x46E8, vga->save_46e8);
70705b261ecSmrg#endif
708f7df2e56Smrg    pci_io_write8(pInt->io, 0x03C3, vga->save_vse);
709f7df2e56Smrg    pci_io_write8(pInt->io, 0x03C2, vga->save_msr);
710af31da9aSmacallan#endif
71105b261ecSmrg}
71205b261ecSmrg
71305b261ecSmrg#if defined (_PC)
71405b261ecSmrgstatic void
71505b261ecSmrgSetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set)
71605b261ecSmrg{
71705b261ecSmrg    int pagesize = getpagesize();
718f7df2e56Smrg    unsigned char *base;
71905b261ecSmrg    int i;
72005b261ecSmrg
721f7df2e56Smrg    if (pci_device_map_legacy
722f7df2e56Smrg        (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base))
723f7df2e56Smrg        return;                 /* eek */
724f7df2e56Smrg
72505b261ecSmrg    if (set) {
726f7df2e56Smrg        for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
727f7df2e56Smrg            MEM_WW(pInt, i, *(base + i));
728f7df2e56Smrg    }
729f7df2e56Smrg    else {
730f7df2e56Smrg        for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
731f7df2e56Smrg            *(base + i) = MEM_RW(pInt, i);
73205b261ecSmrg    }
733f7df2e56Smrg
734f7df2e56Smrg    pci_device_unmap_legacy(pInt->dev, base, pagesize);
73505b261ecSmrg}
73605b261ecSmrg
73705b261ecSmrgvoid
73805b261ecSmrgxf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save)
73905b261ecSmrg{
74005b261ecSmrg    int pagesize = getpagesize();
741f7df2e56Smrg    unsigned char *base;
74205b261ecSmrg    int i;
74305b261ecSmrg
74405b261ecSmrg    if (!xf86IsEntityPrimary(pInt->entityIndex)
745f7df2e56Smrg        || (!save && !pInt->BIOSScratch))
746f7df2e56Smrg        return;
747f7df2e56Smrg
748f7df2e56Smrg    if (pci_device_map_legacy
749f7df2e56Smrg        (pInt->dev, 0, pagesize, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &base))
750f7df2e56Smrg        return;                 /* eek */
751f7df2e56Smrg
75205b261ecSmrg    base += BIOS_SCRATCH_OFF;
75305b261ecSmrg    if (save) {
754f7df2e56Smrg        if ((pInt->BIOSScratch = xnfalloc(BIOS_SCRATCH_LEN)))
755f7df2e56Smrg            for (i = 0; i < BIOS_SCRATCH_LEN; i++)
756f7df2e56Smrg                *(((char *) pInt->BIOSScratch + i)) = *(base + i);
757f7df2e56Smrg    }
758f7df2e56Smrg    else {
759f7df2e56Smrg        if (pInt->BIOSScratch) {
760f7df2e56Smrg            for (i = 0; i < BIOS_SCRATCH_LEN; i++)
761f7df2e56Smrg                *(base + i) = *(pInt->BIOSScratch + i);
762f7df2e56Smrg            free(pInt->BIOSScratch);
763f7df2e56Smrg            pInt->BIOSScratch = NULL;
764f7df2e56Smrg        }
765f7df2e56Smrg    }
766f7df2e56Smrg
767f7df2e56Smrg    pci_device_unmap_legacy(pInt->dev, base - BIOS_SCRATCH_OFF, pagesize);
76805b261ecSmrg}
76905b261ecSmrg#endif
77005b261ecSmrg
77105b261ecSmrgxf86Int10InfoPtr
77205b261ecSmrgxf86InitInt10(int entityIndex)
77305b261ecSmrg{
77405b261ecSmrg    return xf86ExtendedInitInt10(entityIndex, 0);
77505b261ecSmrg}
776