1706f2543Smrg/*
2706f2543Smrg *                   XFree86 int10 module
3706f2543Smrg *   execute BIOS int 10h calls in x86 real mode environment
4706f2543Smrg *                 Copyright 1999 Egbert Eich
5706f2543Smrg *
6706f2543Smrg *   Part of this code was inspired  by the VBIOS POSTing code in DOSEMU
7706f2543Smrg *   developed by the "DOSEMU-Development-Team"
8706f2543Smrg */
9706f2543Smrg
10706f2543Smrg/*
11706f2543Smrg * To debug port accesses define PRINT_PORT to 1.
12706f2543Smrg * Note! You also have to comment out ioperm()
13706f2543Smrg * in xf86EnableIO(). Otherwise we won't trap
14706f2543Smrg * on PIO.
15706f2543Smrg */
16706f2543Smrg
17706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
18706f2543Smrg#include <xorg-config.h>
19706f2543Smrg#endif
20706f2543Smrg
21706f2543Smrg#define PRINT_PORT 0
22706f2543Smrg
23706f2543Smrg#include <unistd.h>
24706f2543Smrg
25706f2543Smrg#include <X11/Xos.h>
26706f2543Smrg#include "xf86.h"
27706f2543Smrg#include "xf86_OSproc.h"
28706f2543Smrg#include "compiler.h"
29706f2543Smrg#define _INT10_PRIVATE
30706f2543Smrg#include "int10Defines.h"
31706f2543Smrg#include "xf86int10.h"
32706f2543Smrg#include "Pci.h"
33706f2543Smrg#ifdef _X86EMU
34706f2543Smrg#include "x86emu/x86emui.h"
35706f2543Smrg#else
36706f2543Smrg#define DEBUG_IO_TRACE() 0
37706f2543Smrg#endif
38706f2543Smrg#include <pciaccess.h>
39706f2543Smrg
40706f2543Smrgstatic int pciCfg1in(CARD16 addr, CARD32 *val);
41706f2543Smrgstatic int pciCfg1out(CARD16 addr, CARD32 val);
42706f2543Smrgstatic int pciCfg1inw(CARD16 addr, CARD16 *val);
43706f2543Smrgstatic int pciCfg1outw(CARD16 addr, CARD16 val);
44706f2543Smrgstatic int pciCfg1inb(CARD16 addr, CARD8 *val);
45706f2543Smrgstatic int pciCfg1outb(CARD16 addr, CARD8 val);
46706f2543Smrg#if defined (_PC)
47706f2543Smrgstatic void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set);
48706f2543Smrg#endif
49706f2543Smrg
50706f2543Smrg#define REG pInt
51706f2543Smrg
52706f2543Smrgint
53706f2543Smrgsetup_int(xf86Int10InfoPtr pInt)
54706f2543Smrg{
55706f2543Smrg    if (pInt != Int10Current) {
56706f2543Smrg	if (!MapCurrentInt10(pInt))
57706f2543Smrg	    return -1;
58706f2543Smrg	Int10Current = pInt;
59706f2543Smrg    }
60706f2543Smrg    X86_EAX = (CARD32) pInt->ax;
61706f2543Smrg    X86_EBX = (CARD32) pInt->bx;
62706f2543Smrg    X86_ECX = (CARD32) pInt->cx;
63706f2543Smrg    X86_EDX = (CARD32) pInt->dx;
64706f2543Smrg    X86_ESI = (CARD32) pInt->si;
65706f2543Smrg    X86_EDI = (CARD32) pInt->di;
66706f2543Smrg    X86_EBP = (CARD32) pInt->bp;
67706f2543Smrg    X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4;
68706f2543Smrg    X86_EIP = 0x0600; X86_CS = 0x0;	/* address of 'hlt' */
69706f2543Smrg    X86_DS = 0x40;			/* standard pc ds */
70706f2543Smrg    X86_ES = pInt->es;
71706f2543Smrg    X86_FS = 0;
72706f2543Smrg    X86_GS = 0;
73706f2543Smrg    X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;
74706f2543Smrg#if defined (_PC)
75706f2543Smrg    if (pInt->Flags & SET_BIOS_SCRATCH)
76706f2543Smrg	SetResetBIOSVars(pInt, TRUE);
77706f2543Smrg#endif
78706f2543Smrg    OsBlockSignals();
79706f2543Smrg    return 0;
80706f2543Smrg}
81706f2543Smrg
82706f2543Smrgvoid
83706f2543Smrgfinish_int(xf86Int10InfoPtr pInt, int sig)
84706f2543Smrg{
85706f2543Smrg    OsReleaseSignals();
86706f2543Smrg    pInt->ax = (CARD32) X86_EAX;
87706f2543Smrg    pInt->bx = (CARD32) X86_EBX;
88706f2543Smrg    pInt->cx = (CARD32) X86_ECX;
89706f2543Smrg    pInt->dx = (CARD32) X86_EDX;
90706f2543Smrg    pInt->si = (CARD32) X86_ESI;
91706f2543Smrg    pInt->di = (CARD32) X86_EDI;
92706f2543Smrg    pInt->es = (CARD16) X86_ES;
93706f2543Smrg    pInt->bp = (CARD32) X86_EBP;
94706f2543Smrg    pInt->flags = (CARD32) X86_FLAGS;
95706f2543Smrg#if defined (_PC)
96706f2543Smrg    if (pInt->Flags & RESTORE_BIOS_SCRATCH)
97706f2543Smrg	SetResetBIOSVars(pInt, FALSE);
98706f2543Smrg#endif
99706f2543Smrg}
100706f2543Smrg
101706f2543Smrg/* general software interrupt handler */
102706f2543SmrgCARD32
103706f2543SmrggetIntVect(xf86Int10InfoPtr pInt,int num)
104706f2543Smrg{
105706f2543Smrg    return MEM_RW(pInt, num << 2) + (MEM_RW(pInt, (num << 2) + 2) << 4);
106706f2543Smrg}
107706f2543Smrg
108706f2543Smrgvoid
109706f2543Smrgpushw(xf86Int10InfoPtr pInt, CARD16 val)
110706f2543Smrg{
111706f2543Smrg    X86_ESP -= 2;
112706f2543Smrg    MEM_WW(pInt, ((CARD32) X86_SS << 4) + X86_SP, val);
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgint
116706f2543Smrgrun_bios_int(int num, xf86Int10InfoPtr pInt)
117706f2543Smrg{
118706f2543Smrg    CARD32 eflags;
119706f2543Smrg#ifndef _PC
120706f2543Smrg    /* check if bios vector is initialized */
121706f2543Smrg    if (MEM_RW(pInt, (num << 2) + 2) == (SYS_BIOS >> 4)) { /* SYS_BIOS_SEG ?*/
122706f2543Smrg
123706f2543Smrg	if (num == 21 && X86_AH == 0x4e) {
124706f2543Smrg 	    xf86DrvMsg(pInt->scrnIndex, X_NOTICE,
125706f2543Smrg		       "Failing Find-Matching-File on non-PC"
126706f2543Smrg			" (int 21, func 4e)\n");
127706f2543Smrg 	    X86_AX = 2;
128706f2543Smrg 	    SET_FLAG(F_CF);
129706f2543Smrg 	    return 1;
130706f2543Smrg 	} else {
131706f2543Smrg	    xf86DrvMsgVerb(pInt->scrnIndex, X_NOT_IMPLEMENTED, 2,
132706f2543Smrg			   "Ignoring int 0x%02x call\n", num);
133706f2543Smrg	    if (xf86GetVerbosity() > 3) {
134706f2543Smrg		dump_registers(pInt);
135706f2543Smrg		stack_trace(pInt);
136706f2543Smrg	    }
137706f2543Smrg	    return 1;
138706f2543Smrg	}
139706f2543Smrg    }
140706f2543Smrg#endif
141706f2543Smrg#ifdef PRINT_INT
142706f2543Smrg    ErrorF("calling card BIOS at: ");
143706f2543Smrg#endif
144706f2543Smrg    eflags = X86_EFLAGS;
145706f2543Smrg#if 0
146706f2543Smrg    eflags = eflags | IF_MASK;
147706f2543Smrg    X86_EFLAGS = X86_EFLAGS  & ~(VIF_MASK | TF_MASK | IF_MASK | NT_MASK);
148706f2543Smrg#endif
149706f2543Smrg    pushw(pInt, eflags);
150706f2543Smrg    pushw(pInt, X86_CS);
151706f2543Smrg    pushw(pInt, X86_IP);
152706f2543Smrg    X86_CS = MEM_RW(pInt, (num << 2) + 2);
153706f2543Smrg    X86_IP = MEM_RW(pInt,  num << 2);
154706f2543Smrg#ifdef PRINT_INT
155706f2543Smrg    ErrorF("0x%x:%lx\n", X86_CS, X86_EIP);
156706f2543Smrg#endif
157706f2543Smrg    return 1;
158706f2543Smrg}
159706f2543Smrg
160706f2543Smrg/* Debugging stuff */
161706f2543Smrgvoid
162706f2543Smrgdump_code(xf86Int10InfoPtr pInt)
163706f2543Smrg{
164706f2543Smrg    int i;
165706f2543Smrg    unsigned long lina = SEG_ADR((CARD32), X86_CS, IP);
166706f2543Smrg
167706f2543Smrg    xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3, "code at 0x%8.8lx:\n", lina);
168706f2543Smrg    for (i=0; i<0x10; i++)
169706f2543Smrg	xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
170706f2543Smrg    xf86ErrorFVerb(3, "\n");
171706f2543Smrg    for (; i<0x20; i++)
172706f2543Smrg	xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, lina + i));
173706f2543Smrg    xf86ErrorFVerb(3, "\n");
174706f2543Smrg}
175706f2543Smrg
176706f2543Smrgvoid
177706f2543Smrgdump_registers(xf86Int10InfoPtr pInt)
178706f2543Smrg{
179706f2543Smrg    xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
180706f2543Smrg	"EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n",
181706f2543Smrg	(unsigned long)X86_EAX, (unsigned long)X86_EBX,
182706f2543Smrg	(unsigned long)X86_ECX, (unsigned long)X86_EDX);
183706f2543Smrg    xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
184706f2543Smrg	"ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n",
185706f2543Smrg	(unsigned long)X86_ESP, (unsigned long)X86_EBP,
186706f2543Smrg	(unsigned long)X86_ESI, (unsigned long)X86_EDI);
187706f2543Smrg    xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
188706f2543Smrg	"CS=0x%4.4x, SS=0x%4.4x,"
189706f2543Smrg	" DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n",
190706f2543Smrg	X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS);
191706f2543Smrg    xf86DrvMsgVerb(pInt->scrnIndex, X_INFO, 3,
192706f2543Smrg	"EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n",
193706f2543Smrg	(unsigned long)X86_EIP, (unsigned long)X86_EFLAGS);
194706f2543Smrg}
195706f2543Smrg
196706f2543Smrgvoid
197706f2543Smrgstack_trace(xf86Int10InfoPtr pInt)
198706f2543Smrg{
199706f2543Smrg    int i = 0;
200706f2543Smrg    unsigned long stack = SEG_ADR((CARD32), X86_SS, SP);
201706f2543Smrg    unsigned long tail  = (CARD32)((X86_SS << 4) + 0x1000);
202706f2543Smrg
203706f2543Smrg    if (stack >= tail) return;
204706f2543Smrg
205706f2543Smrg    xf86MsgVerb(X_INFO, 3, "stack at 0x%8.8lx:\n", stack);
206706f2543Smrg    for (; stack < tail; stack++) {
207706f2543Smrg	xf86ErrorFVerb(3, " %2.2x", MEM_RB(pInt, stack));
208706f2543Smrg	i = (i + 1) % 0x10;
209706f2543Smrg	if (!i)
210706f2543Smrg	    xf86ErrorFVerb(3, "\n");
211706f2543Smrg    }
212706f2543Smrg    if (i)
213706f2543Smrg	xf86ErrorFVerb(3, "\n");
214706f2543Smrg}
215706f2543Smrg
216706f2543Smrgint
217706f2543Smrgport_rep_inb(xf86Int10InfoPtr pInt,
218706f2543Smrg	     CARD16 port, CARD32 base, int d_f, CARD32 count)
219706f2543Smrg{
220706f2543Smrg    register int inc = d_f ? -1 : 1;
221706f2543Smrg    CARD32 dst = base;
222706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
223706f2543Smrg	ErrorF(" rep_insb(%#x) %ld bytes at %8.8lx %s\n",
224706f2543Smrg		port, count, base, d_f ? "up" : "down");
225706f2543Smrg    while (count--) {
226706f2543Smrg	MEM_WB(pInt, dst, x_inb(port));
227706f2543Smrg	dst += inc;
228706f2543Smrg    }
229706f2543Smrg    return dst - base;
230706f2543Smrg}
231706f2543Smrg
232706f2543Smrgint
233706f2543Smrgport_rep_inw(xf86Int10InfoPtr pInt,
234706f2543Smrg	     CARD16 port, CARD32 base, int d_f, CARD32 count)
235706f2543Smrg{
236706f2543Smrg    register int inc = d_f ? -2 : 2;
237706f2543Smrg    CARD32 dst = base;
238706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
239706f2543Smrg	ErrorF(" rep_insw(%#x) %ld bytes at %8.8lx %s\n",
240706f2543Smrg	     port, count, base, d_f ? "up" : "down");
241706f2543Smrg    while (count--) {
242706f2543Smrg	MEM_WW(pInt, dst, x_inw(port));
243706f2543Smrg	dst += inc;
244706f2543Smrg    }
245706f2543Smrg    return dst - base;
246706f2543Smrg}
247706f2543Smrg
248706f2543Smrgint
249706f2543Smrgport_rep_inl(xf86Int10InfoPtr pInt,
250706f2543Smrg	     CARD16 port, CARD32 base, int d_f, CARD32 count)
251706f2543Smrg{
252706f2543Smrg    register int inc = d_f ? -4 : 4;
253706f2543Smrg    CARD32 dst = base;
254706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
255706f2543Smrg	ErrorF(" rep_insl(%#x) %ld bytes at %8.8lx %s\n",
256706f2543Smrg	     port, count, base, d_f ? "up" : "down");
257706f2543Smrg    while (count--) {
258706f2543Smrg	MEM_WL(pInt, dst, x_inl(port));
259706f2543Smrg	dst += inc;
260706f2543Smrg    }
261706f2543Smrg    return dst - base;
262706f2543Smrg}
263706f2543Smrg
264706f2543Smrgint
265706f2543Smrgport_rep_outb(xf86Int10InfoPtr pInt,
266706f2543Smrg	      CARD16 port, CARD32 base, int d_f, CARD32 count)
267706f2543Smrg{
268706f2543Smrg    register int inc = d_f ? -1 : 1;
269706f2543Smrg    CARD32 dst = base;
270706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
271706f2543Smrg	ErrorF(" rep_outb(%#x) %ld bytes at %8.8lx %s\n",
272706f2543Smrg	     port, count, base, d_f ? "up" : "down");
273706f2543Smrg    while (count--) {
274706f2543Smrg	x_outb(port, MEM_RB(pInt, dst));
275706f2543Smrg	dst += inc;
276706f2543Smrg    }
277706f2543Smrg    return dst - base;
278706f2543Smrg}
279706f2543Smrg
280706f2543Smrgint
281706f2543Smrgport_rep_outw(xf86Int10InfoPtr pInt,
282706f2543Smrg	      CARD16 port, CARD32 base, int d_f, CARD32 count)
283706f2543Smrg{
284706f2543Smrg    register int inc = d_f ? -2 : 2;
285706f2543Smrg    CARD32 dst = base;
286706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
287706f2543Smrg	ErrorF(" rep_outw(%#x) %ld bytes at %8.8lx %s\n",
288706f2543Smrg	     port, count, base, d_f ? "up" : "down");
289706f2543Smrg    while (count--) {
290706f2543Smrg	x_outw(port, MEM_RW(pInt, dst));
291706f2543Smrg	dst += inc;
292706f2543Smrg    }
293706f2543Smrg    return dst - base;
294706f2543Smrg}
295706f2543Smrg
296706f2543Smrgint
297706f2543Smrgport_rep_outl(xf86Int10InfoPtr pInt,
298706f2543Smrg	      CARD16 port, CARD32 base, int d_f, CARD32 count)
299706f2543Smrg{
300706f2543Smrg    register int inc = d_f ? -4 : 4;
301706f2543Smrg    CARD32 dst = base;
302706f2543Smrg    if (PRINT_PORT && DEBUG_IO_TRACE())
303706f2543Smrg	ErrorF(" rep_outl(%#x) %ld bytes at %8.8lx %s\n",
304706f2543Smrg	     port, count, base, d_f ? "up" : "down");
305706f2543Smrg    while (count--) {
306706f2543Smrg	x_outl(port, MEM_RL(pInt, dst));
307706f2543Smrg	dst += inc;
308706f2543Smrg    }
309706f2543Smrg    return dst - base;
310706f2543Smrg}
311706f2543Smrg
312706f2543SmrgCARD8
313706f2543Smrgx_inb(CARD16 port)
314706f2543Smrg{
315706f2543Smrg    CARD8 val;
316706f2543Smrg
317706f2543Smrg    if (port == 0x40) {
318706f2543Smrg	Int10Current->inb40time++;
319706f2543Smrg	val = (CARD8)(Int10Current->inb40time >>
320706f2543Smrg		      ((Int10Current->inb40time & 1) << 3));
321706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
322706f2543Smrg	    ErrorF(" inb(%#x) = %2.2x\n", port, val);
323706f2543Smrg#ifdef __NOT_YET__
324706f2543Smrg    } else if (port < 0x0100) {		/* Don't interfere with mainboard */
325706f2543Smrg	val = 0;
326706f2543Smrg	xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2,
327706f2543Smrg	    "inb 0x%4.4x\n", port);
328706f2543Smrg	if (xf86GetVerbosity() > 3) {
329706f2543Smrg	    dump_registers(Int10Current);
330706f2543Smrg	    stack_trace(Int10Current);
331706f2543Smrg	}
332706f2543Smrg#endif /* __NOT_YET__ */
333706f2543Smrg    } else if (!pciCfg1inb(port, &val)) {
334706f2543Smrg	val = inb(Int10Current->ioBase + port);
335706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
336706f2543Smrg	    ErrorF(" inb(%#x) = %2.2x\n", port, val);
337706f2543Smrg    }
338706f2543Smrg    return val;
339706f2543Smrg}
340706f2543Smrg
341706f2543SmrgCARD16
342706f2543Smrgx_inw(CARD16 port)
343706f2543Smrg{
344706f2543Smrg    CARD16 val;
345706f2543Smrg
346706f2543Smrg    if (port == 0x5c) {
347706f2543Smrg	struct timeval tv;
348706f2543Smrg
349706f2543Smrg	/*
350706f2543Smrg	 * Emulate a PC98's timer.  Typical resolution is 3.26 usec.
351706f2543Smrg	 * Approximate this by dividing by 3.
352706f2543Smrg	 */
353706f2543Smrg	X_GETTIMEOFDAY(&tv);
354706f2543Smrg	val = (CARD16)(tv.tv_usec / 3);
355706f2543Smrg    } else if (!pciCfg1inw(port, &val)) {
356706f2543Smrg	val = inw(Int10Current->ioBase + port);
357706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
358706f2543Smrg	    ErrorF(" inw(%#x) = %4.4x\n", port, val);
359706f2543Smrg    }
360706f2543Smrg    return val;
361706f2543Smrg}
362706f2543Smrg
363706f2543Smrgvoid
364706f2543Smrgx_outb(CARD16 port, CARD8 val)
365706f2543Smrg{
366706f2543Smrg    if ((port == 0x43) && (val == 0)) {
367706f2543Smrg	struct timeval tv;
368706f2543Smrg	/*
369706f2543Smrg	 * Emulate a PC's timer 0.  Such timers typically have a resolution of
370706f2543Smrg	 * some .838 usec per tick, but this can only provide 1 usec per tick.
371706f2543Smrg	 * (Not that this matters much, given inherent emulation delays.)  Use
372706f2543Smrg	 * the bottom bit as a byte select.  See inb(0x40) above.
373706f2543Smrg	 */
374706f2543Smrg	X_GETTIMEOFDAY(&tv);
375706f2543Smrg	Int10Current->inb40time = (CARD16)(tv.tv_usec | 1);
376706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
377706f2543Smrg	    ErrorF(" outb(%#x, %2.2x)\n", port, val);
378706f2543Smrg#ifdef __NOT_YET__
379706f2543Smrg    } else if (port < 0x0100) {		/* Don't interfere with mainboard */
380706f2543Smrg	xf86DrvMsgVerb(Int10Current->scrnIndex, X_NOT_IMPLEMENTED, 2,
381706f2543Smrg	    "outb 0x%4.4x,0x%2.2x\n", port, val);
382706f2543Smrg	if (xf86GetVerbosity() > 3) {
383706f2543Smrg	    dump_registers(Int10Current);
384706f2543Smrg	    stack_trace(Int10Current);
385706f2543Smrg	}
386706f2543Smrg#endif /* __NOT_YET__ */
387706f2543Smrg    } else if (!pciCfg1outb(port, val)) {
388706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
389706f2543Smrg	    ErrorF(" outb(%#x, %2.2x)\n", port, val);
390706f2543Smrg	outb(Int10Current->ioBase + port, val);
391706f2543Smrg    }
392706f2543Smrg}
393706f2543Smrg
394706f2543Smrgvoid
395706f2543Smrgx_outw(CARD16 port, CARD16 val)
396706f2543Smrg{
397706f2543Smrg
398706f2543Smrg    if (!pciCfg1outw(port, val)) {
399706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
400706f2543Smrg	    ErrorF(" outw(%#x, %4.4x)\n", port, val);
401706f2543Smrg	outw(Int10Current->ioBase + port, val);
402706f2543Smrg    }
403706f2543Smrg}
404706f2543Smrg
405706f2543SmrgCARD32
406706f2543Smrgx_inl(CARD16 port)
407706f2543Smrg{
408706f2543Smrg    CARD32 val;
409706f2543Smrg
410706f2543Smrg    if (!pciCfg1in(port, &val)) {
411706f2543Smrg	val = inl(Int10Current->ioBase + port);
412706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
413706f2543Smrg	    ErrorF(" inl(%#x) = %8.8lx\n", port, val);
414706f2543Smrg    }
415706f2543Smrg    return val;
416706f2543Smrg}
417706f2543Smrg
418706f2543Smrgvoid
419706f2543Smrgx_outl(CARD16 port, CARD32 val)
420706f2543Smrg{
421706f2543Smrg    if (!pciCfg1out(port, val)) {
422706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
423706f2543Smrg	    ErrorF(" outl(%#x, %8.8lx)\n", port, val);
424706f2543Smrg	outl(Int10Current->ioBase + port, val);
425706f2543Smrg    }
426706f2543Smrg}
427706f2543Smrg
428706f2543SmrgCARD8
429706f2543SmrgMem_rb(CARD32 addr)
430706f2543Smrg{
431706f2543Smrg    return (*Int10Current->mem->rb)(Int10Current, addr);
432706f2543Smrg}
433706f2543Smrg
434706f2543SmrgCARD16
435706f2543SmrgMem_rw(CARD32 addr)
436706f2543Smrg{
437706f2543Smrg    return (*Int10Current->mem->rw)(Int10Current, addr);
438706f2543Smrg}
439706f2543Smrg
440706f2543SmrgCARD32
441706f2543SmrgMem_rl(CARD32 addr)
442706f2543Smrg{
443706f2543Smrg    return (*Int10Current->mem->rl)(Int10Current, addr);
444706f2543Smrg}
445706f2543Smrg
446706f2543Smrgvoid
447706f2543SmrgMem_wb(CARD32 addr, CARD8 val)
448706f2543Smrg{
449706f2543Smrg    (*Int10Current->mem->wb)(Int10Current, addr, val);
450706f2543Smrg}
451706f2543Smrg
452706f2543Smrgvoid
453706f2543SmrgMem_ww(CARD32 addr, CARD16 val)
454706f2543Smrg{
455706f2543Smrg    (*Int10Current->mem->ww)(Int10Current, addr, val);
456706f2543Smrg}
457706f2543Smrg
458706f2543Smrgvoid
459706f2543SmrgMem_wl(CARD32 addr, CARD32 val)
460706f2543Smrg{
461706f2543Smrg    (*Int10Current->mem->wl)(Int10Current, addr, val);
462706f2543Smrg}
463706f2543Smrg
464706f2543Smrgstatic CARD32 PciCfg1Addr = 0;
465706f2543Smrg
466706f2543Smrg#define PCI_DOM_FROM_TAG(tag)  (((tag) >> 24) & (PCI_DOM_MASK))
467706f2543Smrg#define PCI_BUS_FROM_TAG(tag)  (((tag) >> 16) & (PCI_DOMBUS_MASK))
468706f2543Smrg#define PCI_DEV_FROM_TAG(tag)  (((tag) & 0x0000f800u) >> 11)
469706f2543Smrg#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8)
470706f2543Smrg
471706f2543Smrg#define PCI_OFFSET(x) ((x) & 0x000000ff)
472706f2543Smrg#define PCI_TAG(x)    ((x) & 0x7fffff00)
473706f2543Smrg
474706f2543Smrgstatic struct pci_device*
475706f2543Smrgpci_device_for_cfg_address (CARD32 addr)
476706f2543Smrg{
477706f2543Smrg	struct pci_device *dev = NULL;
478706f2543Smrg	PCITAG tag = PCI_TAG(addr);
479706f2543Smrg	struct pci_slot_match slot_match = {
480706f2543Smrg		.domain = PCI_DOM_FROM_TAG(tag),
481706f2543Smrg		.bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)),
482706f2543Smrg		.dev = PCI_DEV_FROM_TAG(tag),
483706f2543Smrg		.func = PCI_FUNC_FROM_TAG(tag),
484706f2543Smrg		.match_data = 0
485706f2543Smrg	};
486706f2543Smrg
487706f2543Smrg	struct pci_device_iterator *iter =
488706f2543Smrg	    pci_slot_match_iterator_create (&slot_match);
489706f2543Smrg
490706f2543Smrg	if (iter)
491706f2543Smrg		dev = pci_device_next(iter);
492706f2543Smrg
493706f2543Smrg	pci_iterator_destroy(iter);
494706f2543Smrg
495706f2543Smrg	return dev;
496706f2543Smrg}
497706f2543Smrg
498706f2543Smrgstatic int
499706f2543SmrgpciCfg1in(CARD16 addr, CARD32 *val)
500706f2543Smrg{
501706f2543Smrg    if (addr == 0xCF8) {
502706f2543Smrg	*val = PciCfg1Addr;
503706f2543Smrg	return 1;
504706f2543Smrg    }
505706f2543Smrg    if (addr == 0xCFC) {
506706f2543Smrg	pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr),
507706f2543Smrg			/*
508706f2543Smrg			 * XXXMRG
509706f2543Smrg			 * this one is OK - CARD32 is "long" for 32 bit
510706f2543Smrg			 * and "int" for 64 bit
511706f2543Smrg			 */
512706f2543Smrg			(uint32_t *)val, PCI_OFFSET(PciCfg1Addr));
513706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
514706f2543Smrg	    ErrorF(" cfg_inl(%#lx) = %8.8lx\n", PciCfg1Addr, *val);
515706f2543Smrg	return 1;
516706f2543Smrg    }
517706f2543Smrg    return 0;
518706f2543Smrg}
519706f2543Smrg
520706f2543Smrgstatic int
521706f2543SmrgpciCfg1out(CARD16 addr, CARD32 val)
522706f2543Smrg{
523706f2543Smrg    if (addr == 0xCF8) {
524706f2543Smrg	PciCfg1Addr = val;
525706f2543Smrg	return 1;
526706f2543Smrg    }
527706f2543Smrg    if (addr == 0xCFC) {
528706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
529706f2543Smrg	    ErrorF(" cfg_outl(%#lx, %8.8lx)\n", PciCfg1Addr, val);
530706f2543Smrg	pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr),
531706f2543Smrg			val, PCI_OFFSET(PciCfg1Addr));
532706f2543Smrg	return 1;
533706f2543Smrg    }
534706f2543Smrg    return 0;
535706f2543Smrg}
536706f2543Smrg
537706f2543Smrgstatic int
538706f2543SmrgpciCfg1inw(CARD16 addr, CARD16 *val)
539706f2543Smrg{
540706f2543Smrg    int shift;
541706f2543Smrg
542706f2543Smrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
543706f2543Smrg	shift = (addr - 0xCF8) * 8;
544706f2543Smrg	*val = (PciCfg1Addr >> shift) & 0xffff;
545706f2543Smrg	return 1;
546706f2543Smrg    }
547706f2543Smrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
548706f2543Smrg	const unsigned offset = addr - 0xCFC;
549706f2543Smrg
550706f2543Smrg	pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr),
551706f2543Smrg			val, PCI_OFFSET(PciCfg1Addr) + offset);
552706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
553706f2543Smrg	    ErrorF(" cfg_inw(%#lx) = %4.4x\n", PciCfg1Addr + offset, *val);
554706f2543Smrg	return 1;
555706f2543Smrg    }
556706f2543Smrg    return 0;
557706f2543Smrg}
558706f2543Smrg
559706f2543Smrgstatic int
560706f2543SmrgpciCfg1outw(CARD16 addr, CARD16 val)
561706f2543Smrg{
562706f2543Smrg    int shift;
563706f2543Smrg
564706f2543Smrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
565706f2543Smrg	shift = (addr - 0xCF8) * 8;
566706f2543Smrg	PciCfg1Addr &= ~(0xffff << shift);
567706f2543Smrg	PciCfg1Addr |= ((CARD32) val) << shift;
568706f2543Smrg	return 1;
569706f2543Smrg    }
570706f2543Smrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
571706f2543Smrg	const unsigned offset = addr - 0xCFC;
572706f2543Smrg
573706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
574706f2543Smrg	    ErrorF(" cfg_outw(%#lx, %4.4x)\n", PciCfg1Addr + offset, val);
575706f2543Smrg	pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr),
576706f2543Smrg			val, PCI_OFFSET(PciCfg1Addr) + offset);
577706f2543Smrg	return 1;
578706f2543Smrg    }
579706f2543Smrg    return 0;
580706f2543Smrg}
581706f2543Smrg
582706f2543Smrgstatic int
583706f2543SmrgpciCfg1inb(CARD16 addr, CARD8 *val)
584706f2543Smrg{
585706f2543Smrg    int shift;
586706f2543Smrg
587706f2543Smrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
588706f2543Smrg	shift = (addr - 0xCF8) * 8;
589706f2543Smrg	*val = (PciCfg1Addr >> shift) & 0xff;
590706f2543Smrg	return 1;
591706f2543Smrg    }
592706f2543Smrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
593706f2543Smrg	const unsigned offset = addr - 0xCFC;
594706f2543Smrg
595706f2543Smrg	pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr),
596706f2543Smrg			val, PCI_OFFSET(PciCfg1Addr) + offset);
597706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
598706f2543Smrg	    ErrorF(" cfg_inb(%#lx) = %2.2x\n", PciCfg1Addr + offset, *val);
599706f2543Smrg	return 1;
600706f2543Smrg    }
601706f2543Smrg    return 0;
602706f2543Smrg}
603706f2543Smrg
604706f2543Smrgstatic int
605706f2543SmrgpciCfg1outb(CARD16 addr, CARD8 val)
606706f2543Smrg{
607706f2543Smrg    int shift;
608706f2543Smrg
609706f2543Smrg    if ((addr >= 0xCF8) && (addr <= 0xCFB)) {
610706f2543Smrg	shift = (addr - 0xCF8) * 8;
611706f2543Smrg	PciCfg1Addr &= ~(0xff << shift);
612706f2543Smrg	PciCfg1Addr |= ((CARD32) val) << shift;
613706f2543Smrg	return 1;
614706f2543Smrg    }
615706f2543Smrg    if ((addr >= 0xCFC) && (addr <= 0xCFF)) {
616706f2543Smrg	const unsigned offset = addr - 0xCFC;
617706f2543Smrg
618706f2543Smrg	if (PRINT_PORT && DEBUG_IO_TRACE())
619706f2543Smrg	    ErrorF(" cfg_outb(%#lx, %2.2x)\n", PciCfg1Addr + offset, val);
620706f2543Smrg	pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr),
621706f2543Smrg			val, PCI_OFFSET(PciCfg1Addr) + offset);
622706f2543Smrg	return 1;
623706f2543Smrg    }
624706f2543Smrg    return 0;
625706f2543Smrg}
626706f2543Smrg
627706f2543SmrgCARD8
628706f2543Smrgbios_checksum(const CARD8 *start, int size)
629706f2543Smrg{
630706f2543Smrg    CARD8 sum = 0;
631706f2543Smrg
632706f2543Smrg    while (size-- > 0)
633706f2543Smrg	sum += *start++;
634706f2543Smrg    return sum;
635706f2543Smrg}
636706f2543Smrg
637706f2543Smrg/*
638706f2543Smrg * Lock/Unlock legacy VGA. Some Bioses try to be very clever and make
639706f2543Smrg * an attempt to detect a legacy ISA card. If they find one they might
640706f2543Smrg * act very strange: for example they might configure the card as a
641706f2543Smrg * monochrome card. This might cause some drivers to choke.
642706f2543Smrg * To avoid this we attempt legacy VGA by writing to all know VGA
643706f2543Smrg * disable registers before we call the BIOS initialization and
644706f2543Smrg * restore the original values afterwards. In beween we hold our
645706f2543Smrg * breath. To get to a (possibly exising) ISA card need to disable
646706f2543Smrg * our current PCI card.
647706f2543Smrg */
648706f2543Smrg/*
649706f2543Smrg * This is just for booting: we just want to catch pure
650706f2543Smrg * legacy vga therefore we don't worry about mmio etc.
651706f2543Smrg * This stuff should really go into vgaHW.c. However then
652706f2543Smrg * the driver would have to load the vga-module prior to
653706f2543Smrg * doing int10.
654706f2543Smrg */
655706f2543Smrgvoid
656706f2543SmrgLockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
657706f2543Smrg{
658706f2543Smrg#ifndef NO_LEGACY_VGA
659706f2543Smrg    vga->save_msr    = inb(pInt->ioBase + 0x03CC);
660706f2543Smrg    vga->save_vse    = inb(pInt->ioBase + 0x03C3);
661706f2543Smrg#ifndef __ia64__
662706f2543Smrg    vga->save_46e8   = inb(pInt->ioBase + 0x46E8);
663706f2543Smrg#endif
664706f2543Smrg    vga->save_pos102 = inb(pInt->ioBase + 0x0102);
665706f2543Smrg    outb(pInt->ioBase + 0x03C2, ~(CARD8)0x03 & vga->save_msr);
666706f2543Smrg    outb(pInt->ioBase + 0x03C3, ~(CARD8)0x01 & vga->save_vse);
667706f2543Smrg#ifndef __ia64__
668706f2543Smrg    outb(pInt->ioBase + 0x46E8, ~(CARD8)0x08 & vga->save_46e8);
669706f2543Smrg#endif
670706f2543Smrg    outb(pInt->ioBase + 0x0102, ~(CARD8)0x01 & vga->save_pos102);
671706f2543Smrg#endif
672706f2543Smrg}
673706f2543Smrg
674706f2543Smrgvoid
675706f2543SmrgUnlockLegacyVGA(xf86Int10InfoPtr pInt, legacyVGAPtr vga)
676706f2543Smrg{
677706f2543Smrg#ifndef NO_LEGACY_VGA
678706f2543Smrg    outb(pInt->ioBase + 0x0102, vga->save_pos102);
679706f2543Smrg#ifndef __ia64__
680706f2543Smrg    outb(pInt->ioBase + 0x46E8, vga->save_46e8);
681706f2543Smrg#endif
682706f2543Smrg    outb(pInt->ioBase + 0x03C3, vga->save_vse);
683706f2543Smrg    outb(pInt->ioBase + 0x03C2, vga->save_msr);
684706f2543Smrg#endif
685706f2543Smrg}
686706f2543Smrg
687706f2543Smrg#if defined (_PC)
688706f2543Smrgstatic void
689706f2543SmrgSetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set)
690706f2543Smrg{
691706f2543Smrg    int pagesize = getpagesize();
692706f2543Smrg    unsigned char* base = xf86MapVidMem(pInt->scrnIndex,
693706f2543Smrg					VIDMEM_MMIO, 0, pagesize);
694706f2543Smrg    int i;
695706f2543Smrg
696706f2543Smrg    if (set) {
697706f2543Smrg	for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
698706f2543Smrg	    MEM_WW(pInt, i, *(base + i));
699706f2543Smrg    } else {
700706f2543Smrg	for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
701706f2543Smrg	    *(base + i) = MEM_RW(pInt, i);
702706f2543Smrg    }
703706f2543Smrg
704706f2543Smrg    xf86UnMapVidMem(pInt->scrnIndex,base,pagesize);
705706f2543Smrg}
706706f2543Smrg
707706f2543Smrgvoid
708706f2543Smrgxf86Int10SaveRestoreBIOSVars(xf86Int10InfoPtr pInt, Bool save)
709706f2543Smrg{
710706f2543Smrg    int pagesize = getpagesize();
711706f2543Smrg    unsigned char* base;
712706f2543Smrg    int i;
713706f2543Smrg
714706f2543Smrg    if (!xf86IsEntityPrimary(pInt->entityIndex)
715706f2543Smrg	|| (!save && !pInt->BIOSScratch))
716706f2543Smrg	return;
717706f2543Smrg
718706f2543Smrg    base = xf86MapVidMem(pInt->scrnIndex, VIDMEM_MMIO, 0, pagesize);
719706f2543Smrg    base += BIOS_SCRATCH_OFF;
720706f2543Smrg    if (save) {
721706f2543Smrg	if ((pInt->BIOSScratch
722706f2543Smrg	     = xnfalloc(BIOS_SCRATCH_LEN)))
723706f2543Smrg	    for (i = 0; i < BIOS_SCRATCH_LEN; i++)
724706f2543Smrg		*(((char*)pInt->BIOSScratch + i)) = *(base + i);
725706f2543Smrg    } else {
726706f2543Smrg	if (pInt->BIOSScratch) {
727706f2543Smrg	    for (i = 0; i < BIOS_SCRATCH_LEN; i++)
728706f2543Smrg		*(base + i) = *(pInt->BIOSScratch + i);
729706f2543Smrg	    free(pInt->BIOSScratch);
730706f2543Smrg	    pInt->BIOSScratch = NULL;
731706f2543Smrg	}
732706f2543Smrg    }
733706f2543Smrg
734706f2543Smrg    xf86UnMapVidMem(pInt->scrnIndex,base - BIOS_SCRATCH_OFF ,pagesize);
735706f2543Smrg}
736706f2543Smrg#endif
737706f2543Smrg
738706f2543Smrgxf86Int10InfoPtr
739706f2543Smrgxf86InitInt10(int entityIndex)
740706f2543Smrg{
741706f2543Smrg    return xf86ExtendedInitInt10(entityIndex, 0);
742706f2543Smrg}
743